From b0fc45f6ca1feb91caba5fc798d7ab81482b3a5d Mon Sep 17 00:00:00 2001 From: Jesse Pearson Date: Thu, 14 Dec 2023 10:02:02 -0400 Subject: [PATCH 1/4] Add Compatibility Service (#7778) --- changelog/update-4163-compatibility-service | 4 ++ includes/class-compatibility-service.php | 61 +++++++++++++++++++ includes/class-wc-payments.php | 11 ++++ includes/core/server/class-request.php | 1 + .../class-wc-payments-api-client.php | 22 +++++++ .../unit/test-class-compatibility-service.php | 61 +++++++++++++++++++ .../test-class-wc-payments-api-client.php | 29 ++++++++- 7 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 changelog/update-4163-compatibility-service create mode 100644 includes/class-compatibility-service.php create mode 100644 tests/unit/test-class-compatibility-service.php diff --git a/changelog/update-4163-compatibility-service b/changelog/update-4163-compatibility-service new file mode 100644 index 00000000000..3a524da05ae --- /dev/null +++ b/changelog/update-4163-compatibility-service @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Adding Compatibility Service to assist with flagging possible compatibility issues in the future. diff --git a/includes/class-compatibility-service.php b/includes/class-compatibility-service.php new file mode 100644 index 00000000000..444b3383cb1 --- /dev/null +++ b/includes/class-compatibility-service.php @@ -0,0 +1,61 @@ +payments_api_client = $payments_api_client; + } + + /** + * Initializes this class's WP hooks. + * + * @return void + */ + public function init_hooks() { + add_action( 'woocommerce_payments_account_refreshed', [ $this, 'update_compatibility_data' ] ); + } + + /** + * Gets the data we need to confirm compatibility and sends it to the server. + * + * @return void + */ + public function update_compatibility_data() { + try { + $this->payments_api_client->update_compatibility_data( + [ + 'woopayments_version' => WCPAY_VERSION_NUMBER, + 'woocommerce_version' => WC_VERSION, + ] + ); + } catch ( API_Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch + // The exception is already logged if logging is on, nothing else needed. + } + } +} diff --git a/includes/class-wc-payments.php b/includes/class-wc-payments.php index f2e038afe59..26e51088d9f 100644 --- a/includes/class-wc-payments.php +++ b/includes/class-wc-payments.php @@ -44,6 +44,7 @@ use WCPay\Internal\Service\OrderService; use WCPay\WooPay\WooPay_Scheduler; use WCPay\WooPay\WooPay_Session; +use WCPay\Compatibility_Service; /** * Main class for the WooPayments extension. Its responsibility is to initialize the extension. @@ -295,6 +296,13 @@ class WC_Payments { */ private static $incentives_service; + /** + * Instance of Compatibility_Service, created in init function + * + * @var Compatibility_Service + */ + private static $compatibility_service; + /** * Entry point to the initialization logic. */ @@ -463,6 +471,7 @@ public static function init() { include_once __DIR__ . '/core/service/class-wc-payments-customer-service-api.php'; include_once __DIR__ . '/class-duplicate-payment-prevention-service.php'; include_once __DIR__ . '/class-wc-payments-incentives-service.php'; + include_once __DIR__ . '/class-compatibility-service.php'; include_once __DIR__ . '/multi-currency/wc-payments-multi-currency.php'; self::$woopay_checkout_service = new Checkout_Service(); @@ -497,6 +506,7 @@ public static function init() { self::$woopay_tracker = new WooPay_Tracker( self::get_wc_payments_http() ); self::$incentives_service = new WC_Payments_Incentives_Service( self::$database_cache ); self::$duplicate_payment_prevention_service = new Duplicate_Payment_Prevention_Service(); + self::$compatibility_service = new Compatibility_Service( self::$api_client ); ( new WooPay_Scheduler( self::$api_client ) )->init(); @@ -505,6 +515,7 @@ public static function init() { self::$fraud_service->init_hooks(); self::$onboarding_service->init_hooks(); 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 ); diff --git a/includes/core/server/class-request.php b/includes/core/server/class-request.php index 80e35dba0de..6264660bb29 100644 --- a/includes/core/server/class-request.php +++ b/includes/core/server/class-request.php @@ -161,6 +161,7 @@ abstract class Request { WC_Payments_API_Client::AUTHORIZATIONS_API => 'authorizations', WC_Payments_API_Client::FRAUD_OUTCOMES_API => 'fraud_outcomes', WC_Payments_API_Client::FRAUD_RULESET_API => 'fraud_ruleset', + WC_Payments_API_Client::COMPATIBILITY_API => 'compatibility', ]; /** diff --git a/includes/wc-payment-api/class-wc-payments-api-client.php b/includes/wc-payment-api/class-wc-payments-api-client.php index f6cd60bfb87..637126b3fa4 100644 --- a/includes/wc-payment-api/class-wc-payments-api-client.php +++ b/includes/wc-payment-api/class-wc-payments-api-client.php @@ -76,6 +76,7 @@ class WC_Payments_API_Client { const FRAUD_SERVICES_API = 'accounts/fraud_services'; const FRAUD_OUTCOMES_API = 'fraud_outcomes'; const FRAUD_RULESET_API = 'fraud_ruleset'; + const COMPATIBILITY_API = 'compatibility'; /** * Common keys in API requests/responses that we might want to redact. @@ -1703,6 +1704,27 @@ public function get_onboarding_po_eligible( array $business_info, array $store_i ); } + /** + * Sends the compatibility data to the server to be saved to the account. + * + * @param array $compatibility_data The array containing the data. + * + * @return array HTTP response on success. + * + * @throws API_Exception - If not connected or request failed. + */ + public function update_compatibility_data( $compatibility_data ) { + $response = $this->request( + [ + 'compatibility_data' => $compatibility_data, + ], + self::COMPATIBILITY_API, + self::POST + ); + + return $response; + } + /** * Sends a request object. * diff --git a/tests/unit/test-class-compatibility-service.php b/tests/unit/test-class-compatibility-service.php new file mode 100644 index 00000000000..70e86b5d2dc --- /dev/null +++ b/tests/unit/test-class-compatibility-service.php @@ -0,0 +1,61 @@ +mock_api_client = $this->createMock( WC_Payments_API_Client::class ); + $this->compatibility_service = new Compatibility_Service( $this->mock_api_client ); + $this->compatibility_service->init_hooks(); + } + + public function test_registers_woocommerce_filters_properly() { + $priority = has_filter( 'woocommerce_payments_account_refreshed', [ $this->compatibility_service, 'update_compatibility_data' ] ); + $this->assertEquals( 10, $priority ); + } + + public function test_update_compatibility_data() { + // Arrange: Create the expected value to be passed to update_compatibility_data. + $expected = [ + 'woopayments_version' => WCPAY_VERSION_NUMBER, + 'woocommerce_version' => WC_VERSION, + ]; + + // Arrange/Assert: Set the expectations for update_compatibility_data. + $this->mock_api_client + ->expects( $this->once() ) + ->method( 'update_compatibility_data' ) + ->with( $expected ); + + // Act: Call the method we're testing. + $this->compatibility_service->update_compatibility_data(); + } +} diff --git a/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php b/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php index 4476cce139a..d6320c14bd0 100644 --- a/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php +++ b/tests/unit/wc-payment-api/test-class-wc-payments-api-client.php @@ -907,7 +907,7 @@ public function test_get_disputes_summary_success() { $this->assertSame( 12, $disputes_summary['data']['count'] ); } - public function get_onboarding_po_eligible() { + public function test_get_onboarding_po_eligible() { $this->set_http_mock_response( 200, [ @@ -1203,6 +1203,33 @@ public function test_request_doesnt_retry_get_without_idempotency_header_on_netw [ [], 'intentions', 'GET' ] ); } + + public function test_update_compatibility_data() { + // Arrange: Set expectation and return for remote_request. + $this->mock_http_client + ->expects( $this->once() ) + ->method( 'remote_request' ) + ->willReturn( + [ + 'body' => wp_json_encode( [ 'result' => 'success' ] ), + 'response' => [ + 'code' => 200, + 'message' => 'OK', + ], + ] + ); + + // Act: Get the result of updating the data. + $result = $this->payments_api_client->update_compatibility_data( + [ + 'woocommerce_core_version' => WC_VERSION, + ] + ); + + // Assert: Confirm we get the expected response. + $this->assertSame( 'success', $result['result'] ); + } + /** * Set up http mock response. * From 6da89587890b77f813e5987362287e84c7102413 Mon Sep 17 00:00:00 2001 From: Zvonimir Maglica Date: Thu, 14 Dec 2023 17:13:28 +0100 Subject: [PATCH 2/4] Descriptive error message when payment method is invalid (#7842) Co-authored-by: Dat Hoang --- changelog/fix-7301-descriptive-error-message-on-invalid-pm | 4 ++++ includes/class-payment-information.php | 2 +- tests/unit/test-class-payment-information.php | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 changelog/fix-7301-descriptive-error-message-on-invalid-pm diff --git a/changelog/fix-7301-descriptive-error-message-on-invalid-pm b/changelog/fix-7301-descriptive-error-message-on-invalid-pm new file mode 100644 index 00000000000..798235980af --- /dev/null +++ b/changelog/fix-7301-descriptive-error-message-on-invalid-pm @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Improved error message for invalid payment method diff --git a/includes/class-payment-information.php b/includes/class-payment-information.php index 8a27682dd7a..1f95a05887d 100644 --- a/includes/class-payment-information.php +++ b/includes/class-payment-information.php @@ -134,7 +134,7 @@ public function __construct( if ( empty( $payment_method ) && empty( $token ) && ! \WC_Payments::is_network_saved_cards_enabled() ) { // If network-wide cards are enabled, a payment method or token may not be specified and the platform default one will be used. throw new Invalid_Payment_Method_Exception( - __( 'Invalid payment method. Please input a new card number.', 'woocommerce-payments' ), + __( 'Invalid or missing payment details. Please ensure the provided payment method is correctly entered.', 'woocommerce-payments' ), 'payment_method_not_provided' ); } diff --git a/tests/unit/test-class-payment-information.php b/tests/unit/test-class-payment-information.php index 3da65eb1501..b6cfd8c3960 100644 --- a/tests/unit/test-class-payment-information.php +++ b/tests/unit/test-class-payment-information.php @@ -34,7 +34,7 @@ public function set_up() { public function test_requires_payment_method_or_token() { $this->expectException( Exception::class ); - $this->expectExceptionMessage( 'Invalid payment method. Please input a new card number.' ); + $this->expectExceptionMessage( 'Invalid or missing payment details. Please ensure the provided payment method is correctly entered.' ); $payment_information = new Payment_Information( '' ); } From 066e8763c9a2fb86285da0cd2fdd1983102275f8 Mon Sep 17 00:00:00 2001 From: Miguel Gasca Date: Thu, 14 Dec 2023 17:19:15 +0100 Subject: [PATCH 3/4] Use CardNotice component for authorization notification in transaction details page (#7891) Co-authored-by: Vladimir Reznichenko --- ...748-capture-notification-styles-are-broken | 4 + client/payment-details/summary/index.tsx | 133 ++++++++---------- .../test/__snapshots__/index.test.tsx.snap | 17 ++- 3 files changed, 76 insertions(+), 78 deletions(-) create mode 100644 changelog/fix-7748-capture-notification-styles-are-broken diff --git a/changelog/fix-7748-capture-notification-styles-are-broken b/changelog/fix-7748-capture-notification-styles-are-broken new file mode 100644 index 00000000000..348106f98f8 --- /dev/null +++ b/changelog/fix-7748-capture-notification-styles-are-broken @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fixed broken styles in authorization capture notifications diff --git a/client/payment-details/summary/index.tsx b/client/payment-details/summary/index.tsx index 6112a27e86f..34887da95db 100644 --- a/client/payment-details/summary/index.tsx +++ b/client/payment-details/summary/index.tsx @@ -5,13 +5,7 @@ */ import { __ } from '@wordpress/i18n'; import { dateI18n } from '@wordpress/date'; -import { - Card, - CardBody, - CardFooter, - CardDivider, - Flex, -} from '@wordpress/components'; +import { Card, CardBody, CardDivider, Flex } from '@wordpress/components'; import moment from 'moment'; import React, { useContext } from 'react'; import { createInterpolateElement } from '@wordpress/element'; @@ -55,6 +49,7 @@ import MissingOrderNotice from 'wcpay/payment-details/summary/missing-order-noti import DisputeAwaitingResponseDetails from '../dispute-details/dispute-awaiting-response-details'; import DisputeResolutionFooter from '../dispute-details/dispute-resolution-footer'; import ErrorBoundary from 'components/error-boundary'; +import CardNotice from 'wcpay/components/card-notice'; declare const window: any; @@ -508,73 +503,69 @@ const PaymentDetailsSummary: React.FC< PaymentDetailsSummaryProps > = ( { authorization && ! authorization.captured && ( - -
-
- { 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 && ( - + ), + } + ) }{ ' ' } + - + > + + { 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