Skip to content

Add seller_message to failed order notes #9934

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading