Date: Wed, 3 Jan 2024 15:44:41 -0500
Subject: [PATCH 05/60] Send metadata in the error message (#7951)
---
changelog/send-metadata-in-error-message | 4 ++++
includes/class-wc-payment-gateway-wcpay.php | 7 ++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
create mode 100644 changelog/send-metadata-in-error-message
diff --git a/changelog/send-metadata-in-error-message b/changelog/send-metadata-in-error-message
new file mode 100644
index 00000000000..1d4c516ae8b
--- /dev/null
+++ b/changelog/send-metadata-in-error-message
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Send metadata in error message
diff --git a/includes/class-wc-payment-gateway-wcpay.php b/includes/class-wc-payment-gateway-wcpay.php
index 32910b60cad..6331101bd25 100644
--- a/includes/class-wc-payment-gateway-wcpay.php
+++ b/includes/class-wc-payment-gateway-wcpay.php
@@ -1463,7 +1463,12 @@ public function process_payment_for_order( $cart, $payment_information, $schedul
$intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0;
if ( $intent_meta_order_id !== $order_id ) {
throw new Intent_Authentication_Exception(
- __( "We're not able to process this payment. Please try again later.", 'woocommerce-payments' ),
+ sprintf(
+ /* translators: %s: metadata. We do not need to translate WooPayMeta */
+ esc_html( __( 'We\'re not able to process this payment. Please try again later. WooPayMeta: intent_meta_order_id: %1$s, order_id: %2$s', 'woocommerce-payments' ) ),
+ esc_attr( $intent_meta_order_id ),
+ esc_attr( $order_id ),
+ ),
'order_id_mismatch'
);
}
From 9e3012962c0a0e0193c83416a6c111f6a0d130ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9sar=20Costa?=
<10233985+cesarcosta99@users.noreply.github.com>
Date: Thu, 4 Jan 2024 16:18:27 -0500
Subject: [PATCH 06/60] Avoid WooPay duplicate charges when order cannot be
completely processed (#7968)
---
changelog/fix-2199-woopay-duplicate-payments | 5 +++++
.../class-duplicate-payment-prevention-service.php | 10 +++++++---
2 files changed, 12 insertions(+), 3 deletions(-)
create mode 100644 changelog/fix-2199-woopay-duplicate-payments
diff --git a/changelog/fix-2199-woopay-duplicate-payments b/changelog/fix-2199-woopay-duplicate-payments
new file mode 100644
index 00000000000..19c6948d923
--- /dev/null
+++ b/changelog/fix-2199-woopay-duplicate-payments
@@ -0,0 +1,5 @@
+Significance: patch
+Type: fix
+Comment: Fix WooPay duplicate charges.
+
+
diff --git a/includes/class-duplicate-payment-prevention-service.php b/includes/class-duplicate-payment-prevention-service.php
index 99f093c5c09..71a0bfbcc10 100644
--- a/includes/class-duplicate-payment-prevention-service.php
+++ b/includes/class-duplicate-payment-prevention-service.php
@@ -102,9 +102,13 @@ public function check_payment_intent_attached_to_order_succeeded( WC_Order $orde
return;
}
- $intent_meta_order_id_raw = $intent->get_metadata()['order_id'] ?? '';
- $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0;
- if ( $intent_meta_order_id !== $order->get_id() ) {
+ $intent_meta_order_id_raw = $intent->get_metadata()['order_id'] ?? '';
+ $intent_meta_order_id = is_numeric( $intent_meta_order_id_raw ) ? intval( $intent_meta_order_id_raw ) : 0;
+ $intent_meta_order_number_raw = $intent->get_metadata()['order_number'] ?? '';
+ $intent_meta_order_number = is_numeric( $intent_meta_order_number_raw ) ? intval( $intent_meta_order_number_raw ) : 0;
+ $paid_on_woopay = filter_var( $intent->get_metadata()['paid_on_woopay'] ?? false, FILTER_VALIDATE_BOOLEAN );
+ $is_woopay_order = $order->get_id() === $intent_meta_order_number;
+ if ( ! ( $paid_on_woopay && $is_woopay_order ) && $intent_meta_order_id !== $order->get_id() ) {
return;
}
From 2a8613820b9e2f3ca3f54639c8d3cb3a97ba199e Mon Sep 17 00:00:00 2001
From: Eric Jinks <3147296+Jinksi@users.noreply.github.com>
Date: Fri, 5 Jan 2024 09:08:12 +1000
Subject: [PATCH 07/60] Hide the transaction details refund menu for
non-refundable disputes (#7962)
---
...-transaction-refund-eligible-disputes-only | 4 ++
client/disputes/utils.ts | 5 ++
client/payment-details/summary/index.tsx | 12 ++++-
.../summary/test/index.test.tsx | 48 +++++++++++++++++++
4 files changed, 68 insertions(+), 1 deletion(-)
create mode 100644 changelog/fix-7960-transaction-refund-eligible-disputes-only
diff --git a/changelog/fix-7960-transaction-refund-eligible-disputes-only b/changelog/fix-7960-transaction-refund-eligible-disputes-only
new file mode 100644
index 00000000000..e35c11107f7
--- /dev/null
+++ b/changelog/fix-7960-transaction-refund-eligible-disputes-only
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Hide the transaction details refund menu for ineligble disputed transactions
diff --git a/client/disputes/utils.ts b/client/disputes/utils.ts
index 6e5acf2f437..d4cb2fc52d1 100644
--- a/client/disputes/utils.ts
+++ b/client/disputes/utils.ts
@@ -72,6 +72,11 @@ export const isInquiry = ( dispute: Pick< Dispute, 'status' > ): boolean => {
return dispute.status.startsWith( 'warning' );
};
+export const isRefundable = ( status: DisputeStatus ): boolean => {
+ // Refundable dispute statuses are one of `warning_needs_response`, `warning_under_review`, `warning_closed` or `won`.
+ return isInquiry( { status } ) || 'won' === status;
+};
+
/**
* Returns the dispute fee balance transaction for a dispute if it exists
* and the deduction has not been reversed.
diff --git a/client/payment-details/summary/index.tsx b/client/payment-details/summary/index.tsx
index 607bacb5f0a..58db34e8da3 100644
--- a/client/payment-details/summary/index.tsx
+++ b/client/payment-details/summary/index.tsx
@@ -48,6 +48,7 @@ import DisputeStatusChip from 'components/dispute-status-chip';
import {
getDisputeFeeFormatted,
isAwaitingResponse,
+ isRefundable,
} from 'wcpay/disputes/utils';
import { useAuthorization } from 'wcpay/data';
import CaptureAuthorizationButton from 'wcpay/components/capture-authorization-button';
@@ -208,6 +209,15 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( {
const disputeFee =
charge.dispute && getDisputeFeeFormatted( charge.dispute );
+ // If this transaction is disputed, check if it is refundable.
+ const isDisputeRefundable = charge.dispute
+ ? isRefundable( charge.dispute.status )
+ : true;
+
+ // Control menu only shows refund actions for now. In the future, it may show other actions.
+ const showControlMenu =
+ charge.captured && ! charge.refunded && isDisputeRefundable;
+
// Use the balance_transaction fee if available. If not (e.g. authorized but not captured), use the application_fee_amount.
const transactionFee = charge.balance_transaction
? {
@@ -484,7 +494,7 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( {
- { ! charge?.refunded && charge?.captured && (
+ { showControlMenu && (
{
screen.getByRole( 'button', {
name: /Accept dispute/,
} );
+
+ // Refund menu is not rendered
+ expect(
+ screen.queryByRole( 'button', {
+ name: /Translation actions/i,
+ } )
+ ).toBeNull();
} );
test( 'renders the information of a disputed charge when the store/charge currency differ', () => {
@@ -684,6 +691,11 @@ describe( 'PaymentDetailsSummary', () => {
name: /Accept/i,
} )
).toBeNull();
+
+ // Refund menu is rendered
+ screen.getByRole( 'button', {
+ name: /Translation actions/i,
+ } );
} );
test( 'correctly renders dispute details for "under_review" disputes', () => {
@@ -712,6 +724,13 @@ describe( 'PaymentDetailsSummary', () => {
name: /Accept/i,
} )
).toBeNull();
+
+ // Refund menu is not rendered
+ expect(
+ screen.queryByRole( 'button', {
+ name: /Translation actions/i,
+ } )
+ ).toBeNull();
} );
test( 'correctly renders dispute details for "accepted" disputes', () => {
@@ -744,6 +763,13 @@ describe( 'PaymentDetailsSummary', () => {
name: /Accept/i,
} )
).toBeNull();
+
+ // Refund menu is not rendered
+ expect(
+ screen.queryByRole( 'button', {
+ name: /Translation actions/i,
+ } )
+ ).toBeNull();
} );
test( 'correctly renders dispute details for "lost" disputes', () => {
@@ -777,6 +803,13 @@ describe( 'PaymentDetailsSummary', () => {
name: /Accept/i,
} )
).toBeNull();
+
+ // Refund menu is not rendered
+ expect(
+ screen.queryByRole( 'button', {
+ name: /Translation actions/i,
+ } )
+ ).toBeNull();
} );
test( 'correctly renders dispute details for "warning_needs_response" inquiry disputes', () => {
@@ -807,6 +840,11 @@ describe( 'PaymentDetailsSummary', () => {
screen.getByRole( 'button', {
name: /Issue refund/i,
} );
+
+ // Refund menu is rendered
+ screen.getByRole( 'button', {
+ name: /Translation actions/i,
+ } );
} );
test( 'correctly renders dispute details for "warning_under_review" inquiry disputes', () => {
@@ -834,6 +872,11 @@ describe( 'PaymentDetailsSummary', () => {
name: /Accept/i,
} )
).toBeNull();
+
+ // Refund menu is rendered
+ screen.getByRole( 'button', {
+ name: /Translation actions/i,
+ } );
} );
test( 'correctly renders dispute details for "warning_closed" inquiry disputes', () => {
@@ -862,6 +905,11 @@ describe( 'PaymentDetailsSummary', () => {
name: /Accept/i,
} )
).toBeNull();
+
+ // Refund menu is rendered
+ screen.getByRole( 'button', {
+ name: /Translation actions/i,
+ } );
} );
describe( 'order missing notice', () => {
From c56dbcf9de0a4eacb6a89cab94e8be55cc91d0dc Mon Sep 17 00:00:00 2001
From: Eric Jinks <3147296+Jinksi@users.noreply.github.com>
Date: Fri, 5 Jan 2024 15:58:06 +1000
Subject: [PATCH 08/60] Fix missing transaction error when viewing orders
placed in mismatched test mode (#7972)
---
...-7967-disputed-order-notice-test-mode-check | 4 ++++
client/order/index.js | 7 +++++--
includes/admin/class-wc-payments-admin.php | 18 ++++++++++++++++++
3 files changed, 27 insertions(+), 2 deletions(-)
create mode 100644 changelog/fix-7967-disputed-order-notice-test-mode-check
diff --git a/changelog/fix-7967-disputed-order-notice-test-mode-check b/changelog/fix-7967-disputed-order-notice-test-mode-check
new file mode 100644
index 00000000000..43f8af2c81b
--- /dev/null
+++ b/changelog/fix-7967-disputed-order-notice-test-mode-check
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix network error that occurs when viewing an test mode order with test mode disabled, and vice versa.
diff --git a/client/order/index.js b/client/order/index.js
index 1bfdfeee7ad..16ec2b60183 100644
--- a/client/order/index.js
+++ b/client/order/index.js
@@ -61,6 +61,9 @@ jQuery( function ( $ ) {
const manualRefundsTip = getConfig( 'manualRefundsTip' ) ?? '';
const chargeId = getConfig( 'chargeId' );
const testMode = getConfig( 'testMode' );
+ // Order and site are both in test mode, or both in live mode.
+ // '1' = true, '' = false, null = the order was created before the test mode meta was added, so we assume it matches.
+ const orderTestModeMatch = getConfig( 'orderTestModeMatch' ) !== '';
maybeShowOrderNotices();
@@ -175,7 +178,7 @@ jQuery( function ( $ ) {
'#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 the container doesn't exist (WC < 7.9) don't render notices.
if ( ! container ) {
return;
}
@@ -184,7 +187,7 @@ jQuery( function ( $ ) {
<>
{ testMode && }
- { chargeId && (
+ { chargeId && orderTestModeMatch && (
get_payment_method() ) {
$refund_amount = $order->get_remaining_refund_amount();
+
+ // Check if the order's test mode meta matches the site's current test mode state.
+ // E.g. order and site are both in test mode, or both in live mode.
+ $order_mode = $order->get_meta( WC_Payments_Order_Service::WCPAY_MODE_META_KEY );
+ if ( '' === $order_mode ) {
+ // If the order doesn't have a mode set, assume it was created before the order mode meta was added (< 6.9 PR#7651) and return null.
+ $order_test_mode_match = null;
+ } else {
+ $order_test_mode_match = (
+ \WCPay\Constants\Order_Mode::PRODUCTION === $order_mode &&
+ WC_Payments::mode()->is_live()
+ ) || (
+ \WCPay\Constants\Order_Mode::TEST === $order_mode &&
+ WC_Payments::mode()->is_test()
+ );
+ }
+
wp_localize_script(
'WCPAY_ADMIN_ORDER_ACTIONS',
'wcpay_order_config',
@@ -736,6 +753,7 @@ public function enqueue_payments_scripts() {
'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 ),
+ 'orderTestModeMatch' => $order_test_mode_match,
]
);
wp_localize_script(
From c02877a5e56d94afc6c280eea1ece9cc19372224 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?K=C4=81rlis=20Janisels?=
Date: Fri, 5 Jan 2024 11:34:12 +0200
Subject: [PATCH 09/60] Fix the typo for transaction controls label (#7979)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Kārlis Janisels
---
changelog/fix-7964-typo-for-transaction-actions | 5 +++++
client/payment-details/summary/index.tsx | 2 +-
.../test/__snapshots__/index.test.tsx.snap | 14 +++++++-------
.../payment-details/summary/test/index.test.tsx | 16 ++++++++--------
.../test/__snapshots__/index.test.tsx.snap | 2 +-
5 files changed, 22 insertions(+), 17 deletions(-)
create mode 100644 changelog/fix-7964-typo-for-transaction-actions
diff --git a/changelog/fix-7964-typo-for-transaction-actions b/changelog/fix-7964-typo-for-transaction-actions
new file mode 100644
index 00000000000..603667aa9a7
--- /dev/null
+++ b/changelog/fix-7964-typo-for-transaction-actions
@@ -0,0 +1,5 @@
+Significance: patch
+Type: fix
+Comment: Fixed a typo
+
+
diff --git a/client/payment-details/summary/index.tsx b/client/payment-details/summary/index.tsx
index 58db34e8da3..0d9ea81fa93 100644
--- a/client/payment-details/summary/index.tsx
+++ b/client/payment-details/summary/index.tsx
@@ -502,7 +502,7 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( {