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;
|
||||
|
||||
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
|
||||
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
|
||||
|
||||
/**
|
||||
* CartUpdateCustomer class.
|
||||
|
@ -215,6 +216,19 @@ class CartUpdateCustomer extends AbstractCartRoute {
|
|||
* @return array
|
||||
*/
|
||||
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 [
|
||||
'first_name' => $customer->get_billing_first_name(),
|
||||
'last_name' => $customer->get_billing_last_name(),
|
||||
|
@ -222,9 +236,9 @@ class CartUpdateCustomer extends AbstractCartRoute {
|
|||
'address_1' => $customer->get_billing_address_1(),
|
||||
'address_2' => $customer->get_billing_address_2(),
|
||||
'city' => $customer->get_billing_city(),
|
||||
'state' => $customer->get_billing_state(),
|
||||
'state' => $billing_state,
|
||||
'postcode' => $customer->get_billing_postcode(),
|
||||
'country' => $customer->get_billing_country(),
|
||||
'country' => $billing_country,
|
||||
'phone' => $customer->get_billing_phone(),
|
||||
'email' => $customer->get_billing_email(),
|
||||
];
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
|
||||
|
||||
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
|
||||
|
||||
/**
|
||||
* AddressSchema class.
|
||||
*
|
||||
|
@ -87,6 +89,8 @@ abstract class AbstractAddressSchema extends AbstractSchema {
|
|||
* @return array
|
||||
*/
|
||||
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['country'] = wc_strtoupper( wc_clean( wp_unslash( $address['country'] ) ) );
|
||||
$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_2'] = wc_clean( wp_unslash( $address['address_2'] ) );
|
||||
$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['phone'] = wc_clean( wp_unslash( $address['phone'] ) );
|
||||
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.
|
||||
*
|
||||
|
@ -164,8 +116,9 @@ abstract class AbstractAddressSchema extends AbstractSchema {
|
|||
* @return true|\WP_Error
|
||||
*/
|
||||
public function validate_callback( $address, $request, $param ) {
|
||||
$errors = new \WP_Error();
|
||||
$address = $this->sanitize_callback( $address, $request, $param );
|
||||
$errors = new \WP_Error();
|
||||
$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 ) ) {
|
||||
$errors->add(
|
||||
|
@ -179,14 +132,14 @@ abstract class AbstractAddressSchema extends AbstractSchema {
|
|||
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(
|
||||
'invalid_state',
|
||||
sprintf(
|
||||
/* 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' ),
|
||||
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;
|
||||
|
||||
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
|
||||
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
|
||||
|
||||
/**
|
||||
* BillingAddressSchema class.
|
||||
|
@ -89,11 +90,12 @@ class BillingAddressSchema extends AbstractAddressSchema {
|
|||
* @return stdClass
|
||||
*/
|
||||
public function get_item_response( $address ) {
|
||||
$validation_util = new ValidationUtils();
|
||||
if ( ( $address instanceof \WC_Customer || $address instanceof \WC_Order ) ) {
|
||||
$billing_country = $address->get_billing_country();
|
||||
$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 = '';
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
|
||||
|
||||
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
|
||||
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
|
||||
|
||||
/**
|
||||
* ShippingAddressSchema class.
|
||||
|
@ -32,11 +33,12 @@ class ShippingAddressSchema extends AbstractAddressSchema {
|
|||
* @return stdClass
|
||||
*/
|
||||
public function get_item_response( $address ) {
|
||||
$validation_util = new ValidationUtils();
|
||||
if ( ( $address instanceof \WC_Customer || $address instanceof \WC_Order ) ) {
|
||||
$shipping_country = $address->get_shipping_country();
|
||||
$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 = '';
|
||||
}
|
||||
|
||||
|
|
|
@ -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