From ad7111c4a692723d4fdaa99e647b9d134fb9a370 Mon Sep 17 00:00:00 2001 From: James Allan Date: Thu, 21 Dec 2023 11:12:39 +1000 Subject: [PATCH 1/4] 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 2/4] 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 ? ( + + ) : ( + <> + ) } > { __( - '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 && ( - - - - - } - 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 ( + + + + + } + 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`] = ` +
+

+

+
+
+ +
+

+
+
+ +
+

+
+
+ +
+

- 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.
+
+
+ +
+

+

+

+
+
+ +
+

+
+
+ +
+

+
+
+ +
+

+
+ + + +

+
+
+ +
+

+