Skip to content

Commit

Permalink
Add seller_message to failed order notes (#9934)
Browse files Browse the repository at this point in the history
  • Loading branch information
htdat authored Dec 19, 2024
1 parent 7b6e7ef commit 5005b6b
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 2 deletions.
4 changes: 4 additions & 0 deletions changelog/feat-9810-add-seller-message
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Add seller_message to failed order notes
17 changes: 16 additions & 1 deletion includes/class-wc-payment-gateway-wcpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,19 @@
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, Invalid_Address_Exception, Fraud_Prevention_Enabled_Exception, Invalid_Phone_Number_Exception, Rate_Limiter_Enabled_Exception, Order_ID_Mismatch_Exception, Order_Not_Found_Exception, New_Process_Payment_Exception };
use WCPay\Exceptions\{Add_Payment_Method_Exception,
Amount_Too_Small_Exception,
API_Merchant_Exception,
Process_Payment_Exception,
Intent_Authentication_Exception,
API_Exception,
Invalid_Address_Exception,
Fraud_Prevention_Enabled_Exception,
Invalid_Phone_Number_Exception,
Rate_Limiter_Enabled_Exception,
Order_ID_Mismatch_Exception,
Order_Not_Found_Exception,
New_Process_Payment_Exception};
use WCPay\Core\Server\Request\Cancel_Intention;
use WCPay\Core\Server\Request\Capture_Intention;
use WCPay\Core\Server\Request\Create_And_Confirm_Intention;
Expand Down Expand Up @@ -1270,6 +1282,9 @@ public function process_payment( $order_id ) {
);

$error_details = esc_html( rtrim( $e->getMessage(), '.' ) );
if ( $e instanceof API_Merchant_Exception ) {
$error_details = $error_details . '. ' . esc_html( rtrim( $e->get_merchant_message(), '.' ) );
}

if ( $e instanceof API_Exception && 'card_error' === $e->get_error_type() ) {
// If the payment failed with a 'card_error' API exception, initialize the fraud meta box
Expand Down
1 change: 1 addition & 0 deletions includes/class-wc-payments.php
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ public static function init() {

include_once __DIR__ . '/exceptions/class-base-exception.php';
include_once __DIR__ . '/exceptions/class-api-exception.php';
include_once __DIR__ . '/exceptions/class-api-merchant-exception.php';
include_once __DIR__ . '/exceptions/class-connection-exception.php';
include_once __DIR__ . '/core/class-mode.php';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use WCPay\Core\Server\Request\Get_Intention;
use WCPay\Exceptions\API_Exception;
use WCPay\Exceptions\API_Merchant_Exception;
use WCPay\Exceptions\Invalid_Payment_Method_Exception;
use WCPay\Exceptions\Add_Payment_Method_Exception;
use WCPay\Exceptions\Order_Not_Found_Exception;
Expand Down Expand Up @@ -342,6 +343,11 @@ public function scheduled_subscription_payment( $amount, $renewal_order ) {
$renewal_order->update_status( 'failed' );

if ( ! empty( $payment_information ) ) {
$error_details = esc_html( rtrim( $e->getMessage(), '.' ) );
if ( $e instanceof API_Merchant_Exception ) {
$error_details = $error_details . '. ' . esc_html( rtrim( $e->get_merchant_message(), '.' ) );
}

$note = sprintf(
WC_Payments_Utils::esc_interpolated_html(
/* translators: %1: the failed payment amount, %2: error message */
Expand All @@ -358,7 +364,7 @@ public function scheduled_subscription_payment( $amount, $renewal_order ) {
wc_price( $amount, [ 'currency' => WC_Payments_Utils::get_order_intent_currency( $renewal_order ) ] ),
$renewal_order
),
esc_html( rtrim( $e->getMessage(), '.' ) )
$error_details
);
$renewal_order->add_order_note( $note );
}
Expand Down
49 changes: 49 additions & 0 deletions includes/exceptions/class-api-merchant-exception.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
/**
* Class API_Merchant_Exception
*
* @package WooCommerce\Payments
*/

namespace WCPay\Exceptions;

defined( 'ABSPATH' ) || exit;

/**
* Class extending API_Exception to include the error message for merchants only.
*/
class API_Merchant_Exception extends API_Exception {
/**
* Merchant message. This message should not be shown to shoppers.
*
* @var string
*/
private $merchant_message;

/**
* Constructor
*
* @param string $message The Exception message to throw.
* @param string $error_code Error code returned by the server, for example wcpay_account_not_found.
* @param int $http_code HTTP response code.
* @param string $merchant_message The merchant message. This message should not be shown to shoppers.
* @param string|null $error_type Error type attribute.
* @param string|null $decline_code The decline code if it is a card error.
* @param int $code The Exception code.
* @param \Throwable|null $previous The previous exception used for the exception chaining.
*/
public function __construct( $message, $error_code, $http_code, $merchant_message, $error_type = null, $decline_code = null, $code = 0, $previous = null ) {
$this->merchant_message = $merchant_message;

parent::__construct( $message, $error_code, $http_code, $error_type, $decline_code, $code, $previous );
}

/**
* Returns the merchant message.
*
* @return string Merchant message.
*/
public function get_merchant_message(): string {
return $this->merchant_message;
}
}
8 changes: 8 additions & 0 deletions includes/wc-payment-api/class-wc-payments-api-client.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use WCPay\Constants\Intent_Status;
use WCPay\Exceptions\API_Exception;
use WCPay\Exceptions\API_Merchant_Exception;
use WCPay\Exceptions\Amount_Too_Small_Exception;
use WCPay\Exceptions\Amount_Too_Large_Exception;
use WCPay\Exceptions\Connection_Exception;
Expand Down Expand Up @@ -2419,6 +2420,13 @@ protected function check_response_for_errors( $response ) {
);

Logger::error( "$error_message ($error_code)" );

if ( 'card_declined' === $error_code && isset( $response_body['error']['payment_intent']['charges']['data'][0]['outcome']['seller_message'] ) ) {
$merchant_message = $response_body['error']['payment_intent']['charges']['data'][0]['outcome']['seller_message'];

throw new API_Merchant_Exception( $message, $error_code, $response_code, $merchant_message, $error_type, $decline_code );
}

throw new API_Exception( $message, $error_code, $response_code, $error_type, $decline_code );
}
}
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/wc-payment-api/test-class-wc-payments-api-client.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

use WCPay\Constants\Country_Code;
use WCPay\Constants\Intent_Status;
use WCPay\Core\Server\Request\Create_And_Confirm_Intention;
use WCPay\Exceptions\API_Exception;
use WCPay\Exceptions\API_Merchant_Exception;
use WCPay\Internal\Logger;
use WCPay\Exceptions\Connection_Exception;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
Expand Down Expand Up @@ -1195,6 +1197,24 @@ public function test_get_tracking_info() {
$this->assertEquals( $expect, $result );
}

public function test_throws_api_merchant_exception() {
$mock_response = [];
$mock_response['error']['code'] = 'card_declined';
$mock_response['error']['payment_intent']['charges']['data'][0]['outcome']['seller_message'] = 'Bank declined';
$this->set_http_mock_response(
401,
$mock_response
);

try {
// This is a dummy call to trigger the response so that our test can validate the exception.
$this->payments_api_client->create_subscription();
} catch ( API_Merchant_Exception $e ) {
$this->assertSame( 'card_declined', $e->get_error_code() );
$this->assertSame( 'Bank declined', $e->get_merchant_message() );
}
}

/**
* Set up http mock response.
*
Expand Down

0 comments on commit 5005b6b

Please sign in to comment.