Skip to content

Commit

Permalink
Allow Afterpay to process payments when the state field is optional (…
Browse files Browse the repository at this point in the history
…UK and NZ customers) (#9079)

Co-authored-by: Samir Merchant <[email protected]>
  • Loading branch information
danielmx-dev and FangedParakeet authored Jul 16, 2024
1 parent d6c8dc4 commit 71203da
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: fix

Allow Afterpay gateway to process payments when the state/county is optional for GB and NZ addresses.
28 changes: 27 additions & 1 deletion includes/class-wc-payment-gateway-wcpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -4501,7 +4501,33 @@ private function upe_needs_redirection( $payment_methods ) {
* @return void
*/
private function handle_afterpay_shipping_requirement( WC_Order $order, Create_And_Confirm_Intention $request ): void {
$check_if_usable = function ( array $address ): bool {
$wc_locale_data = WC()->countries->get_country_locale();

$check_if_usable = function ( array $address ) use ( $wc_locale_data ): bool {
if ( $address['country'] && isset( $wc_locale_data[ $address['country'] ] ) ) {
$country_locale_data = $wc_locale_data[ $address['country'] ];
$fields_to_check = [
'state' => 'state',
'city' => 'city',
'postcode' => 'postal_code',
'address_1' => 'line1',
];

foreach ( $fields_to_check as $locale_field => $address_field ) {
$is_field_required = (
! isset( $country_locale_data[ $locale_field ] ) ||
! isset( $country_locale_data[ $locale_field ]['required'] ) ||
$country_locale_data[ $locale_field ]['required']
);

if ( $is_field_required && ! $address[ $address_field ] ) {
return false;
}
}

return true;
}

return $address['country'] && $address['state'] && $address['city'] && $address['postal_code'] && $address['line1'];
};

Expand Down
5 changes: 3 additions & 2 deletions tests/WCPAY_UnitTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,15 @@ public function createMock( string $original_class_name ): MockObject { // phpcs
* @param mixed $response The expected response.
* @param WC_Payments_API_Client $api_client_mock Specific API client mock if necessary.
* @param WC_Payments_Http $http_mock Specific HTTP mock if necessary.
* @param bool $force_request_mock When true, a request will be mocked even if $total_api_calls is 0.
*
* @return Request|MockObject The mocked request.
*/
protected function mock_wcpay_request( string $request_class, int $total_api_calls = 1, $request_class_constructor_id = null, $response = null, $api_client_mock = null, $http_mock = null ) {
protected function mock_wcpay_request( string $request_class, int $total_api_calls = 1, $request_class_constructor_id = null, $response = null, $api_client_mock = null, $http_mock = null, $force_request_mock = false ) {
$http_mock = $http_mock ? $http_mock : $this->createMock( WC_Payments_Http::class );
$api_client_mock = $api_client_mock ? $api_client_mock : $this->createMock( WC_Payments_API_Client::class );

if ( 1 > $total_api_calls ) {
if ( 1 > $total_api_calls && ! $force_request_mock ) {
$api_client_mock->expects( $this->never() )->method( 'send_request' );

// No expectation for calls, return here.
Expand Down
126 changes: 126 additions & 0 deletions tests/unit/test-class-wc-payment-gateway-wcpay.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use WCPay\Core\Server\Request\Get_Charge;
use WCPay\Core\Server\Request\Get_Intention;
use WCPay\Core\Server\Request\Get_Setup_Intention;
use WCPay\Constants\Country_Code;
use WCPay\Constants\Order_Status;
use WCPay\Constants\Intent_Status;
use WCPay\Constants\Payment_Method;
Expand All @@ -21,6 +22,7 @@
use WCPay\Exceptions\Amount_Too_Small_Exception;
use WCPay\Exceptions\API_Exception;
use WCPay\Exceptions\Fraud_Prevention_Enabled_Exception;
use WCPay\Exceptions\Invalid_Address_Exception;
use WCPay\Exceptions\Process_Payment_Exception;
use WCPay\Exceptions\Order_ID_Mismatch_Exception;
use WCPay\Fraud_Prevention\Fraud_Prevention_Service;
Expand Down Expand Up @@ -188,6 +190,13 @@ class WC_Payment_Gateway_WCPay_Test extends WCPAY_UnitTestCase {
*/
private $mock_duplicates_detection_service;

/**
* Backup of WC locale data
*
* @var array
*/
private $locale_backup;

/**
* Pre-test setup
*/
Expand Down Expand Up @@ -269,6 +278,8 @@ public function set_up() {
->method( 'get_payment_metadata' )
->willReturn( [] );
wcpay_get_test_container()->replace( OrderService::class, $mock_order_service );

$this->locale_backup = WC()->countries->get_country_locale();
}

/**
Expand Down Expand Up @@ -305,6 +316,7 @@ public function tear_down() {

wcpay_get_test_container()->reset_all_replacements();
WC()->session->set( 'wc_notices', [] );
WC()->countries->locale = $this->locale_backup;
}

public function test_process_redirect_payment_intent_processing() {
Expand Down Expand Up @@ -2825,6 +2837,120 @@ public function test_process_payment_for_order_upe_payment_method() {
$this->card_gateway->process_payment_for_order( WC()->cart, $pi );
}

/**
* @dataProvider process_payment_for_order_afterpay_clearpay_provider
*/
public function test_process_payment_for_order_afterpay_clearpay( array $address, array $locale_data, ?string $expected_exception ) {
$payment_method = 'woocommerce_payments_afterpay_clearpay';
$expected_upe_payment_method_for_pi_creation = 'afterpay_clearpay';
$order = WC_Helper_Order::create_order();
$order->set_currency( 'USD' );
$order->set_total( 100 );
$order->set_billing_city( $address['city'] );
$order->set_billing_state( $address['state'] );
$order->set_billing_postcode( $address['postcode'] );
$order->set_billing_country( $address['country'] );
$order->save();

$_POST['wcpay-fraud-prevention-token'] = 'correct-token';
$_POST['payment_method'] = $payment_method;
$pi = new Payment_Information( 'pm_test', $order, null, null, null, null, null, '', 'afterpay_clearpay' );

if ( $expected_exception ) {
$this->mock_wcpay_request( Create_And_Confirm_Intention::class, 0, null, null, null, null, true );
$this->expectException( $expected_exception );
} else {
$request = $this->mock_wcpay_request( Create_And_Confirm_Intention::class );
$request->expects( $this->once() )
->method( 'set_payment_methods' )
->with( [ $expected_upe_payment_method_for_pi_creation ] );
$request->expects( $this->once() )
->method( 'format_response' )
->willReturn( WC_Helper_Intention::create_intention( [ 'status' => 'success' ] ) );
}

WC()->countries->locale = $locale_data;

$afterpay_gateway = current(
array_filter(
$this->gateways,
function ( $gateway ) {
return $gateway->get_payment_method()->get_id() === 'afterpay_clearpay';
}
)
);

$afterpay_gateway->process_payment_for_order( WC()->cart, $pi );
}

public function process_payment_for_order_afterpay_clearpay_provider() {
return [
'with valid full address' => [
'address' => [
'city' => 'WooCity',
'state' => 'NY',
'postcode' => '12345',
'country' => Country_Code::UNITED_STATES,
],
// An empty locale data means all fields should be required.
'locale_data' => [],
'expected_exception' => null,
],
'with incomplete address' => [
'address' => [
'city' => 'WooCity',
'state' => '',
'postcode' => '12345',
'country' => Country_Code::UNITED_STATES,
],
'locale_data' => [
// A missing `required` attribute means that the field will be required.
Country_Code::UNITED_STATES => [ 'state' => [ 'label' => 'State' ] ],
],
'expected_exception' => Invalid_Address_Exception::class,
],
'optional state' => [
'address' => [
'city' => 'London',
'state' => '',
'postcode' => 'HA9 9LY',
'country' => Country_Code::UNITED_KINGDOM,
],
'locale_data' => [
Country_Code::UNITED_KINGDOM => [ 'state' => [ 'required' => false ] ],
],
'expected_exception' => null,
],
'optional state and postcode' => [
'address' => [
'city' => 'London',
'state' => '',
'postcode' => '',
'country' => Country_Code::UNITED_KINGDOM,
],
'locale_data' => [
Country_Code::UNITED_KINGDOM => [
'state' => [ 'required' => false ],
'postcode' => [ 'required' => false ],
],
],
'expected_exception' => null,
],
'optional state, invalid address' => [
'address' => [
'city' => '',
'state' => 'London',
'postcode' => 'HA9 9LY',
'country' => Country_Code::UNITED_KINGDOM,
],
'locale_data' => [
Country_Code::UNITED_KINGDOM => [ 'state' => [ 'required' => false ] ],
],
'expected_exception' => Invalid_Address_Exception::class,
],
];
}

public function test_process_payment_caches_mimimum_amount_and_displays_error_upon_exception() {
delete_transient( 'wcpay_minimum_amount_usd' );

Expand Down

0 comments on commit 71203da

Please sign in to comment.