Unset default customer state if it doesn't match country (https://github.com/woocommerce/woocommerce-blocks/pull/8460)
* Unset default state * add controller for customers * rename validation file * explain fix inline * address feedback * revert back state logic * Update src/StoreApi/Utilities/ValidationUtils.php Co-authored-by: Mike Jolley <mike.jolley@me.com> --------- Co-authored-by: Mike Jolley <mike.jolley@me.com>
This commit is contained in:
parent
817b159e5c
commit
9dcf435569
|
@ -2,6 +2,7 @@
|
||||||
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
|
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
|
||||||
|
|
||||||
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
|
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
|
||||||
|
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CartUpdateCustomer class.
|
* CartUpdateCustomer class.
|
||||||
|
@ -215,6 +216,19 @@ class CartUpdateCustomer extends AbstractCartRoute {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function get_customer_billing_address( \WC_Customer $customer ) {
|
protected function get_customer_billing_address( \WC_Customer $customer ) {
|
||||||
|
$validation_util = new ValidationUtils();
|
||||||
|
$billing_country = $customer->get_billing_country();
|
||||||
|
$billing_state = $customer->get_billing_state();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There's a bug in WooCommerce core in which not having a state ("") would result in us validating against the store's state.
|
||||||
|
* This resets the state to an empty string if it doesn't match the country.
|
||||||
|
*
|
||||||
|
* @todo Removing this handling once we fix the issue with the state value always being the store one.
|
||||||
|
*/
|
||||||
|
if ( ! $validation_util->validate_state( $billing_state, $billing_country ) ) {
|
||||||
|
$billing_state = '';
|
||||||
|
}
|
||||||
return [
|
return [
|
||||||
'first_name' => $customer->get_billing_first_name(),
|
'first_name' => $customer->get_billing_first_name(),
|
||||||
'last_name' => $customer->get_billing_last_name(),
|
'last_name' => $customer->get_billing_last_name(),
|
||||||
|
@ -222,9 +236,9 @@ class CartUpdateCustomer extends AbstractCartRoute {
|
||||||
'address_1' => $customer->get_billing_address_1(),
|
'address_1' => $customer->get_billing_address_1(),
|
||||||
'address_2' => $customer->get_billing_address_2(),
|
'address_2' => $customer->get_billing_address_2(),
|
||||||
'city' => $customer->get_billing_city(),
|
'city' => $customer->get_billing_city(),
|
||||||
'state' => $customer->get_billing_state(),
|
'state' => $billing_state,
|
||||||
'postcode' => $customer->get_billing_postcode(),
|
'postcode' => $customer->get_billing_postcode(),
|
||||||
'country' => $customer->get_billing_country(),
|
'country' => $billing_country,
|
||||||
'phone' => $customer->get_billing_phone(),
|
'phone' => $customer->get_billing_phone(),
|
||||||
'email' => $customer->get_billing_email(),
|
'email' => $customer->get_billing_email(),
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
|
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AddressSchema class.
|
* AddressSchema class.
|
||||||
*
|
*
|
||||||
|
@ -87,6 +89,8 @@ abstract class AbstractAddressSchema extends AbstractSchema {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function sanitize_callback( $address, $request, $param ) {
|
public function sanitize_callback( $address, $request, $param ) {
|
||||||
|
$validation_util = new ValidationUtils();
|
||||||
|
|
||||||
$address = array_merge( array_fill_keys( array_keys( $this->get_properties() ), '' ), (array) $address );
|
$address = array_merge( array_fill_keys( array_keys( $this->get_properties() ), '' ), (array) $address );
|
||||||
$address['country'] = wc_strtoupper( wc_clean( wp_unslash( $address['country'] ) ) );
|
$address['country'] = wc_strtoupper( wc_clean( wp_unslash( $address['country'] ) ) );
|
||||||
$address['first_name'] = wc_clean( wp_unslash( $address['first_name'] ) );
|
$address['first_name'] = wc_clean( wp_unslash( $address['first_name'] ) );
|
||||||
|
@ -95,64 +99,12 @@ abstract class AbstractAddressSchema extends AbstractSchema {
|
||||||
$address['address_1'] = wc_clean( wp_unslash( $address['address_1'] ) );
|
$address['address_1'] = wc_clean( wp_unslash( $address['address_1'] ) );
|
||||||
$address['address_2'] = wc_clean( wp_unslash( $address['address_2'] ) );
|
$address['address_2'] = wc_clean( wp_unslash( $address['address_2'] ) );
|
||||||
$address['city'] = wc_clean( wp_unslash( $address['city'] ) );
|
$address['city'] = wc_clean( wp_unslash( $address['city'] ) );
|
||||||
$address['state'] = $this->format_state( wc_clean( wp_unslash( $address['state'] ) ), $address['country'] );
|
$address['state'] = $validation_util->format_state( wc_clean( wp_unslash( $address['state'] ) ), $address['country'] );
|
||||||
$address['postcode'] = $address['postcode'] ? wc_format_postcode( wc_clean( wp_unslash( $address['postcode'] ) ), $address['country'] ) : '';
|
$address['postcode'] = $address['postcode'] ? wc_format_postcode( wc_clean( wp_unslash( $address['postcode'] ) ), $address['country'] ) : '';
|
||||||
$address['phone'] = wc_clean( wp_unslash( $address['phone'] ) );
|
$address['phone'] = wc_clean( wp_unslash( $address['phone'] ) );
|
||||||
return $address;
|
return $address;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get list of states for a country.
|
|
||||||
*
|
|
||||||
* @param string $country Country code.
|
|
||||||
* @return array Array of state names indexed by state keys.
|
|
||||||
*/
|
|
||||||
protected function get_states_for_country( $country ) {
|
|
||||||
return $country ? array_filter( (array) \wc()->countries->get_states( $country ) ) : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate provided state against a countries list of defined states.
|
|
||||||
*
|
|
||||||
* If there are no defined states for a country, any given state is valid.
|
|
||||||
*
|
|
||||||
* @param string $state State name or code (sanitized).
|
|
||||||
* @param string $country Country code.
|
|
||||||
* @return boolean Valid or not valid.
|
|
||||||
*/
|
|
||||||
protected function validate_state( $state, $country ) {
|
|
||||||
$states = $this->get_states_for_country( $country );
|
|
||||||
|
|
||||||
if ( count( $states ) && ! in_array( \wc_strtoupper( $state ), array_map( '\wc_strtoupper', array_keys( $states ) ), true ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a state based on the country. If country has defined states, will return a valid upper case state code.
|
|
||||||
*
|
|
||||||
* @param string $state State name or code (sanitized).
|
|
||||||
* @param string $country Country code.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function format_state( $state, $country ) {
|
|
||||||
$states = $this->get_states_for_country( $country );
|
|
||||||
|
|
||||||
if ( count( $states ) ) {
|
|
||||||
$state = \wc_strtoupper( $state );
|
|
||||||
$state_values = array_map( 'wc_strtoupper', array_flip( array_map( '\wc_strtoupper', $states ) ) );
|
|
||||||
|
|
||||||
if ( isset( $state_values[ $state ] ) ) {
|
|
||||||
// Convert to state code if a state name was provided.
|
|
||||||
return $state_values[ $state ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the given address object.
|
* Validate the given address object.
|
||||||
*
|
*
|
||||||
|
@ -166,6 +118,7 @@ abstract class AbstractAddressSchema extends AbstractSchema {
|
||||||
public function validate_callback( $address, $request, $param ) {
|
public function validate_callback( $address, $request, $param ) {
|
||||||
$errors = new \WP_Error();
|
$errors = new \WP_Error();
|
||||||
$address = $this->sanitize_callback( $address, $request, $param );
|
$address = $this->sanitize_callback( $address, $request, $param );
|
||||||
|
$validation_util = new ValidationUtils();
|
||||||
|
|
||||||
if ( ! empty( $address['country'] ) && ! in_array( $address['country'], array_keys( wc()->countries->get_countries() ), true ) ) {
|
if ( ! empty( $address['country'] ) && ! in_array( $address['country'], array_keys( wc()->countries->get_countries() ), true ) ) {
|
||||||
$errors->add(
|
$errors->add(
|
||||||
|
@ -179,14 +132,14 @@ abstract class AbstractAddressSchema extends AbstractSchema {
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! empty( $address['state'] ) && ! $this->validate_state( $address['state'], $address['country'] ) ) {
|
if ( ! empty( $address['state'] ) && ! $validation_util->validate_state( $address['state'], $address['country'] ) ) {
|
||||||
$errors->add(
|
$errors->add(
|
||||||
'invalid_state',
|
'invalid_state',
|
||||||
sprintf(
|
sprintf(
|
||||||
/* translators: %1$s given state, %2$s valid states */
|
/* translators: %1$s given state, %2$s valid states */
|
||||||
__( 'The provided state (%1$s) is not valid. Must be one of: %2$s', 'woo-gutenberg-products-block' ),
|
__( 'The provided state (%1$s) is not valid. Must be one of: %2$s', 'woo-gutenberg-products-block' ),
|
||||||
esc_html( $address['state'] ),
|
esc_html( $address['state'] ),
|
||||||
implode( ', ', array_keys( $this->get_states_for_country( $address['country'] ) ) )
|
implode( ', ', array_keys( $validation_util->get_states_for_country( $address['country'] ) ) )
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
|
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
|
||||||
|
|
||||||
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
|
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
|
||||||
|
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BillingAddressSchema class.
|
* BillingAddressSchema class.
|
||||||
|
@ -89,11 +90,12 @@ class BillingAddressSchema extends AbstractAddressSchema {
|
||||||
* @return stdClass
|
* @return stdClass
|
||||||
*/
|
*/
|
||||||
public function get_item_response( $address ) {
|
public function get_item_response( $address ) {
|
||||||
|
$validation_util = new ValidationUtils();
|
||||||
if ( ( $address instanceof \WC_Customer || $address instanceof \WC_Order ) ) {
|
if ( ( $address instanceof \WC_Customer || $address instanceof \WC_Order ) ) {
|
||||||
$billing_country = $address->get_billing_country();
|
$billing_country = $address->get_billing_country();
|
||||||
$billing_state = $address->get_billing_state();
|
$billing_state = $address->get_billing_state();
|
||||||
|
|
||||||
if ( ! $this->validate_state( $billing_state, $billing_country ) ) {
|
if ( ! $validation_util->validate_state( $billing_state, $billing_country ) ) {
|
||||||
$billing_state = '';
|
$billing_state = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
|
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
|
||||||
|
|
||||||
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
|
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
|
||||||
|
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ShippingAddressSchema class.
|
* ShippingAddressSchema class.
|
||||||
|
@ -32,11 +33,12 @@ class ShippingAddressSchema extends AbstractAddressSchema {
|
||||||
* @return stdClass
|
* @return stdClass
|
||||||
*/
|
*/
|
||||||
public function get_item_response( $address ) {
|
public function get_item_response( $address ) {
|
||||||
|
$validation_util = new ValidationUtils();
|
||||||
if ( ( $address instanceof \WC_Customer || $address instanceof \WC_Order ) ) {
|
if ( ( $address instanceof \WC_Customer || $address instanceof \WC_Order ) ) {
|
||||||
$shipping_country = $address->get_shipping_country();
|
$shipping_country = $address->get_shipping_country();
|
||||||
$shipping_state = $address->get_shipping_state();
|
$shipping_state = $address->get_shipping_state();
|
||||||
|
|
||||||
if ( ! $this->validate_state( $shipping_state, $shipping_country ) ) {
|
if ( ! $validation_util->validate_state( $shipping_state, $shipping_country ) ) {
|
||||||
$shipping_state = '';
|
$shipping_state = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
namespace Automattic\WooCommerce\StoreApi\Utilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ValidationUtils class.
|
||||||
|
* Helper class which validates and update customer info.
|
||||||
|
*/
|
||||||
|
class ValidationUtils {
|
||||||
|
/**
|
||||||
|
* Get list of states for a country.
|
||||||
|
*
|
||||||
|
* @param string $country Country code.
|
||||||
|
* @return array Array of state names indexed by state keys.
|
||||||
|
*/
|
||||||
|
public function get_states_for_country( $country ) {
|
||||||
|
return $country ? array_filter( (array) \wc()->countries->get_states( $country ) ) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate provided state against a countries list of defined states.
|
||||||
|
*
|
||||||
|
* If there are no defined states for a country, any given state is valid.
|
||||||
|
*
|
||||||
|
* @param string $state State name or code (sanitized).
|
||||||
|
* @param string $country Country code.
|
||||||
|
* @return boolean Valid or not valid.
|
||||||
|
*/
|
||||||
|
public function validate_state( $state, $country ) {
|
||||||
|
$states = $this->get_states_for_country( $country );
|
||||||
|
|
||||||
|
if ( count( $states ) && ! in_array( \wc_strtoupper( $state ), array_map( '\wc_strtoupper', array_keys( $states ) ), true ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a state based on the country. If country has defined states, will return a valid upper case state code.
|
||||||
|
*
|
||||||
|
* @param string $state State name or code (sanitized).
|
||||||
|
* @param string $country Country code.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function format_state( $state, $country ) {
|
||||||
|
$states = $this->get_states_for_country( $country );
|
||||||
|
|
||||||
|
if ( count( $states ) ) {
|
||||||
|
$state = \wc_strtoupper( $state );
|
||||||
|
$state_values = array_map( '\wc_strtoupper', array_flip( array_map( '\wc_strtoupper', $states ) ) );
|
||||||
|
|
||||||
|
if ( isset( $state_values[ $state ] ) ) {
|
||||||
|
// Convert to state code if a state name was provided.
|
||||||
|
return $state_values[ $state ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $state;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue