Skip to content
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

feat: For Shipping Zones Zip Regex - Correctly handle UK postcodes redacted by Apple Pay #3592

Merged
merged 12 commits into from
Dec 26, 2024
Merged
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*** Changelog ***

= 9.1.0 - xxxx-xx-xx =
* Fix - Correctly handles UK postcodes redacted by Apple Pay.
* Tweak - Avoid re-sending Processing Order customer email when merchant wins dispute.
* Fix - Allow the saving of iDEAL tokens when SEPA is disabled.
* Fix - Fixes the incompatibility notice in editor due missing style property when instantiating Stripe payment methods.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,13 +322,34 @@ private function get_default_shipping_option() {
public function get_normalized_postal_code( $postcode, $country ) {
/**
* Currently, Apple Pay truncates the UK and Canadian postal codes to the first 4 and 3 characters respectively
* Apple Pay also truncates Canadian postal codes to the first 4 characters.
* when passing it back from the shippingcontactselected object. This causes WC to invalidate
* the postal code and not calculate shipping zones correctly.
*/
if ( 'GB' === $country ) {
// Replaces a redacted string with something like LN10***.
return str_pad( preg_replace( '/\s+/', '', $postcode ), 7, '*' );
// UK Postcodes returned from Apple Pay can be alpha numeric 2 chars, 3 chars, or 4 chars long will optionally have a trailing space,
// depending on whether the customer put a space in their postcode between the outcode and incode part.
// See https://assets.publishing.service.gov.uk/media/5a7b997d40f0b62826a049e0/ILRSpecification2013_14Appendix_C_Dec2012_v1.pdf for more details.

// Here is a table showing the functionality by example:
// Original | Apple Pay | Normalized
// 'LN10 1AA' | 'LN10 ' | 'LN10 ***'
// 'LN101AA' | 'LN10' | 'LN10 ***'
// 'W10 2AA' | 'W10 ' | 'W10 ***'
// 'W102AA' | 'W10' | 'W10 ***'
// 'N2 3AA | 'N2 ' | 'N2 ***'
// 'N23AA | 'N2' | 'N2 ***'

$spaceless_postcode = preg_replace( '/\s+/', '', $postcode );

if ( strlen( $spaceless_postcode ) < 5 ) {
// Always reintroduce the space so that Shipping Zones regex like 'N1 *' work to match N1 postcodes like N1 1AA, but don't match N10 postcodes like N10 1AA
return $spaceless_postcode . ' ***';
}

return $postcode; // 5 or more chars means it probably wasn't redacted and will likely validate unchanged.
}

if ( 'CA' === $country ) {
// Replaces a redacted string with something like L4Y***.
return str_pad( preg_replace( '/\s+/', '', $postcode ), 6, '*' );
Expand Down
29 changes: 25 additions & 4 deletions includes/payment-methods/class-wc-stripe-payment-request.php
Original file line number Diff line number Diff line change
Expand Up @@ -512,14 +512,35 @@ public function filter_gateway_title( $title, $id ) {
*/
public function get_normalized_postal_code( $postcode, $country ) {
/**
* Currently, Apple Pay truncates the UK and Canadian postal codes to the first 4 and 3 characters respectively
* when passing it back from the shippingcontactselected object. This causes WC to invalidate
* Currently, Apple Pay truncates the UK postcodes by removing the "inward" (last 3 chars) of the postcode.
* Apple Pay also truncates Canadian postal codes to the first 4 characters.
* When either of these are passed back from the shippingcontactselected object. This causes WC to invalidate
* the postal code and not calculate shipping zones correctly.
*/
if ( 'GB' === $country ) {
// Replaces a redacted string with something like LN10***.
return str_pad( preg_replace( '/\s+/', '', $postcode ), 7, '*' );
// UK Postcodes returned from Apple Pay can be alpha numeric 2 chars, 3 chars, or 4 chars long will optionally have a trailing space,
// depending on whether the customer put a space in their postcode between the outcode and incode part.
// See https://assets.publishing.service.gov.uk/media/5a7b997d40f0b62826a049e0/ILRSpecification2013_14Appendix_C_Dec2012_v1.pdf for more details.

// Here is a table showing the functionality by example:
// Original | Apple Pay | Normalized
// 'LN10 1AA' | 'LN10 ' | 'LN10 ***'
// 'LN101AA' | 'LN10' | 'LN10 ***'
// 'W10 2AA' | 'W10 ' | 'W10 ***'
// 'W102AA' | 'W10' | 'W10 ***'
// 'N2 3AA | 'N2 ' | 'N2 ***'
// 'N23AA | 'N2' | 'N2 ***'

$spaceless_postcode = preg_replace( '/\s+/', '', $postcode );

if ( strlen( $spaceless_postcode ) < 5 ) {
// Always reintroduce the space so that Shipping Zones regex like 'N1 *' work to match N1 postcodes like N1 1AA, but don't match N10 postcodes like N10 1AA
return $spaceless_postcode . ' ***';
}

return $postcode; // 5 or more chars means it probably wasn't redacted and will likely validate unchanged.
}

if ( 'CA' === $country ) {
// Replaces a redacted string with something like L4Y***.
return str_pad( preg_replace( '/\s+/', '', $postcode ), 6, '*' );
Expand Down
1 change: 1 addition & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
== Changelog ==

= 9.1.0 - xxxx-xx-xx =
* Fix - Correctly handles UK postcodes redacted by Apple Pay.
* Tweak - Avoid re-sending Processing Order customer email when merchant wins dispute.
* Fix - Allow the saving of iDEAL tokens when SEPA is disabled.
* Fix - Fixes the incompatibility notice in editor due missing style property when instantiating Stripe payment methods.
Expand Down
46 changes: 45 additions & 1 deletion tests/phpunit/test-wc-stripe-express-checkout-helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public function test_hides_ece_if_cannot_compute_taxes() {
if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) {
define( 'WOOCOMMERCE_CHECKOUT', true );
}
$original_gateways = WC()->payment_gateways()->payment_gateways;
$original_gateways = WC()->payment_gateways()->payment_gateways;
WC()->payment_gateways()->payment_gateways = [
'stripe' => new WC_Gateway_Stripe(),
];
Expand Down Expand Up @@ -267,4 +267,48 @@ public function test_is_account_creation_possible() {
update_option( 'woocommerce_enable_signup_from_checkout_for_subscriptions', 'yes' );
$this->assertTrue( $wc_stripe_ece_helper_mock2->is_account_creation_possible() );
}

/**
* Test for `get_normalized_postal_code`.
*
* @param string $postal_code Postal code.
* @param string $country Country code.
* @param string $expected Expected normalized postal code.
* @return void
* @dataProvider provide_test_get_normalized_postal_code
*/
public function test_get_normalized_postal_code( $postal_code, $country, $expected ) {
$wc_stripe_ece_helper = new WC_Stripe_Express_Checkout_Helper();
$this->assertEquals( $expected, $wc_stripe_ece_helper->get_normalized_postal_code( $postal_code, $country ) );
}

/**
* Provider for `test_get_normalized_postal_code`.
*
* @return array
*/
public function provide_test_get_normalized_postal_code() {
return [
'GB country' => [
'postal code' => 'SW1A 1AA',
'country' => 'GB',
'expected' => 'SW1A 1AA',
],
'GB country, redacted' => [
'postal code' => 'SW1A',
'country' => 'GB',
'expected' => 'SW1A ***',
],
'CA country' => [
'postal code' => 'K1A ',
'country' => 'CA',
'expected' => 'K1A***',
],
'US country' => [
'postal code' => '12345',
'country' => 'US',
'expected' => '12345',
],
];
}
}
Loading