Check if the order needs shipping before validating shipping address (#51630)

This commit is contained in:
Thomas Roberts 2024-09-24 12:53:24 +01:00 committed by GitHub
parent 442cb4e81b
commit 94460bb394
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 109 additions and 1 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fix an issue where virtual products could not be purchased when using the Additional Fields API

View File

@ -201,6 +201,7 @@ class Checkout extends AbstractCartRoute {
$address_fields = $this->additional_fields_controller->get_fields_for_location( 'address' );
if ( ! empty( $address_fields ) ) {
$needs_shipping = WC()->cart->needs_shipping();
foreach ( $address_fields as $field_key => $address_field ) {
if ( $address_field['required'] && ! isset( $request['billing_address'][ $field_key ] ) ) {
throw new RouteException(
@ -210,7 +211,7 @@ class Checkout extends AbstractCartRoute {
400
);
}
if ( $address_field['required'] && ! isset( $request['shipping_address'][ $field_key ] ) ) {
if ( $needs_shipping && $address_field['required'] && ! isset( $request['shipping_address'][ $field_key ] ) ) {
throw new RouteException(
'woocommerce_rest_checkout_missing_required_field',
/* translators: %s: is the field label */

View File

@ -72,6 +72,24 @@ class AdditionalFields extends MockeryTestCase {
'weight' => 10,
)
),
$fixtures->get_simple_product(
array(
'name' => 'Virtual Test Product 3',
'stock_status' => 'instock',
'regular_price' => 10,
'weight' => 10,
'virtual' => true,
)
),
$fixtures->get_simple_product(
array(
'name' => 'Downloadable Test Product 4',
'stock_status' => 'instock',
'regular_price' => 10,
'weight' => 10,
'downloadable' => true,
)
),
);
$this->reset_session();
}
@ -1682,6 +1700,91 @@ class AdditionalFields extends MockeryTestCase {
$this->assertFalse( $this->controller->is_field( $id ), \sprintf( '%s is still registered', $id ) );
}
/**
* Ensures an order for a virtual product can be placed without a shipping address, but an order for a downloadable
* non-virtual cannot.
*/
public function test_place_virtual_downloadable_product_order() {
WC()->cart->empty_cart();
WC()->cart->add_to_cart( $this->products[2]->get_id(), 2 );
$id = 'plugin-namespace/my-required-field';
$label = 'My Required Field';
\woocommerce_register_additional_checkout_field(
array(
'id' => $id,
'label' => $label,
'location' => 'address',
'type' => 'text',
'required' => true,
)
);
$request = new \WP_REST_Request( 'POST', '/wc/store/v1/checkout' );
$request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
$request->set_body_params(
array(
'billing_address' => (object) array(
'first_name' => 'test',
'last_name' => 'test',
'company' => '',
'address_1' => 'test',
'address_2' => '',
'city' => 'test',
'state' => '',
'postcode' => 'cb241ab',
'country' => 'GB',
'phone' => '',
'email' => 'testaccount@test.com',
'plugin-namespace/gov-id' => 'gov id',
'plugin-namespace/my-required-field' => 'req. field',
),
'payment_method' => 'bacs',
'additional_fields' => array(
'plugin-namespace/job-function' => 'engineering',
),
)
);
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status(), print_r( $data, true ) );
// Test with downloadable, but not virtual product.
WC()->cart->empty_cart();
WC()->cart->add_to_cart( $this->products[3]->get_id(), 2 );
$request = new \WP_REST_Request( 'POST', '/wc/store/v1/checkout' );
$request->set_header( 'Nonce', wp_create_nonce( 'wc_store_api' ) );
$request->set_body_params(
array(
'billing_address' => (object) array(
'first_name' => 'test',
'last_name' => 'test',
'company' => '',
'address_1' => 'test',
'address_2' => '',
'city' => 'test',
'state' => '',
'postcode' => 'cb241ab',
'country' => 'GB',
'phone' => '',
'email' => 'testaccount@test.com',
'plugin-namespace/gov-id' => 'gov id',
'plugin-namespace/my-required-field' => 'req. field',
),
'payment_method' => 'bacs',
'additional_fields' => array(
'plugin-namespace/job-function' => 'engineering',
),
)
);
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
// The product is downloadable, but not virtual, so should still require a shipping address.
$this->assertEquals( 400, $response->get_status(), print_r( $data, true ) );
$this->assertEquals( 'There was a problem with the provided shipping address: Government ID is required', $data['message'], print_r( $data, true ) );
}
/**
* Ensures an error is returned when required fields in Contact are missing.
*/