- 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 5/6] 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 6/6] 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 && (
-
+ { /* Use wrapping div to keep buttons grouped together. */ }
+
+
+
+
+
+
+ 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`] = `
+
+
+
+
+ Account Tools
+
+
+ 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.
+
+`;
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
-
+
+
+
+ Account Tools
+
+
+ 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.
+