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

Adjust auto-sync shipping option #2526

Merged
Merged
45 changes: 26 additions & 19 deletions js/src/components/shipping-rate-section/shipping-rate-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import RadioHelperText from '.~/wcdl/radio-helper-text';
import AppDocumentationLink from '.~/components/app-documentation-link';
import VerticalGapLayout from '.~/components/vertical-gap-layout';
import FlatShippingRatesInputCards from './flat-shipping-rates-input-cards';
import useSettings from '.~/components/free-listings/configure-product-listings/useSettings';
import useMCSetup from '.~/hooks/useMCSetup';

/**
* @fires gla_documentation_link_click with `{ context: 'setup-mc-shipping', link_id: 'shipping-read-more', href: 'https://support.google.com/merchants/answer/7050921' }`
Expand All @@ -22,8 +24,16 @@ import FlatShippingRatesInputCards from './flat-shipping-rates-input-cards';

const ShippingRateSection = () => {
const { getInputProps, values } = useAdaptiveFormContext();
const { settings } = useSettings();
const { hasFinishedResolution, data: mcSetup } = useMCSetup();
const inputProps = getInputProps( 'shipping_rate' );

// Hide the automatic shipping rate option if there are no shipping rates and the merchant is onboarding.
const hideAutomatticShippingRate =
! settings?.shipping_rates_count &&
hasFinishedResolution &&
mcSetup?.status === 'incomplete';

return (
<Section
title={ __( 'Shipping rates', 'google-listings-and-ads' ) }
Expand Down Expand Up @@ -51,27 +61,24 @@ const ShippingRateSection = () => {
<Section.Card>
<Section.Card.Body>
<VerticalGapLayout size="large">
<AppRadioContentControl
{ ...inputProps }
label={ createInterpolateElement(
__(
'<strong>Recommended:</strong> Automatically sync my store’s shipping settings to Google.',
'google-listings-and-ads'
),
{
strong: <strong></strong>,
}
) }
value="automatic"
collapsible
>
<RadioHelperText>
{ __(
'My current settings and any future changes to my store’s shipping rates and classes will be automatically synced to Google Merchant Center.',
{ ! hideAutomatticShippingRate && (
<AppRadioContentControl
{ ...inputProps }
label={ __(
'Automatically sync my store’s shipping settings to Google.',
'google-listings-and-ads'
) }
</RadioHelperText>
</AppRadioContentControl>
value="automatic"
collapsible
>
<RadioHelperText>
{ __(
'My current settings and any future changes to my store’s shipping rates and classes will be automatically synced to Google Merchant Center.',
'google-listings-and-ads'
) }
</RadioHelperText>
</AppRadioContentControl>
) }
<AppRadioContentControl
{ ...inputProps }
label={ __(
Expand Down
211 changes: 211 additions & 0 deletions js/src/components/shipping-rate-section/shipping-rate-section.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/**
* External dependencies
*/
import '@testing-library/jest-dom';
import { render } from '@testing-library/react';

/**
* Internal dependencies
*/
import useSettings from '.~/components/free-listings/configure-product-listings/useSettings';
import useMCSetup from '.~/hooks/useMCSetup';
import ShippingRateSection from './shipping-rate-section';
//import FlatShippingRatesInputCards from './flat-shipping-rates-input-cards';

jest.mock( './flat-shipping-rates-input-cards', () => () => <></> );

jest.mock( '.~/components/adaptive-form', () => ( {
useAdaptiveFormContext: jest
.fn()
.mockName( 'useAdaptiveFormContext' )
.mockImplementation( () => {
return {
getInputProps: () => {
return {
checked: true,
className: '',
help: null,
onBlur: () => {},
onChange: () => {},
selected: 'flat',
value: 'flat',
};
},
values: {
countries: [ 'ES' ],
language: 'English',
locale: 'en_US',
location: 'selected',
offer_free_shipping: false,
shipping_country_rates: [],
shipping_country_times: [],
shipping_rate: 'flat',
shipping_time: 'flat',
tax_rate: null,
},
};
} ),
} ) );

jest.mock(
'.~/components/free-listings/configure-product-listings/useSettings'
);
jest.mock( '.~/hooks/useMCSetup' );

describe( 'ShippingRateSection', () => {
it( 'shouldnt render automatic rates if there are not shipping rates and it is onboarding', () => {
useMCSetup.mockImplementation( () => {
return {
hasFinishedResolution: true,
data: {
status: 'incomplete',
},
};
} );

useSettings.mockImplementation( () => {
return {
settings: {
shipping_rates_count: 0,
},
};
} );

const { getByText, queryByRole } = render( <ShippingRateSection /> );

expect(
getByText(
'My shipping settings are simple. I can manually estimate flat shipping rates.'
)
).toBeInTheDocument();

expect(
getByText(
'My shipping settings are complex. I will enter my shipping rates and times manually in Google Merchant Center.'
)
).toBeInTheDocument();

expect(
queryByRole(
'Automatically sync my store’s shipping settings to Google.'
)
).not.toBeInTheDocument();
} );

it( 'should render automatic rates if there are shipping rates and it is onboarding', () => {
useMCSetup.mockImplementation( () => {
return {
hasFinishedResolution: true,
data: {
status: 'incomplete',
},
};
} );

useSettings.mockImplementation( () => {
return {
settings: {
shipping_rates_count: 1,
},
};
} );

const { getByText } = render( <ShippingRateSection /> );

expect(
getByText(
'My shipping settings are simple. I can manually estimate flat shipping rates.'
)
).toBeInTheDocument();

expect(
getByText(
'My shipping settings are complex. I will enter my shipping rates and times manually in Google Merchant Center.'
)
).toBeInTheDocument();

expect(
getByText(
'Automatically sync my store’s shipping settings to Google.'
)
).toBeInTheDocument();
} );

it( 'should render automatic rates if there are not shipping rates and it is not onboarding', () => {
useMCSetup.mockImplementation( () => {
return {
hasFinishedResolution: true,
data: {
status: 'completed',
},
};
} );

useSettings.mockImplementation( () => {
return {
settings: {
shipping_rates_count: 0,
},
};
} );

const { getByText } = render( <ShippingRateSection /> );

expect(
getByText(
'My shipping settings are simple. I can manually estimate flat shipping rates.'
)
).toBeInTheDocument();

expect(
getByText(
'My shipping settings are complex. I will enter my shipping rates and times manually in Google Merchant Center.'
)
).toBeInTheDocument();

expect(
getByText(
'Automatically sync my store’s shipping settings to Google.'
)
).toBeInTheDocument();
} );

it( 'should render automatic rates if there are shipping rates and it is not onboarding', () => {
useMCSetup.mockImplementation( () => {
return {
hasFinishedResolution: true,
data: {
status: 'completed',
},
};
} );

useSettings.mockImplementation( () => {
return {
settings: {
shipping_rates_count: 1,
},
};
} );

const { getByText } = render( <ShippingRateSection /> );

expect(
getByText(
'My shipping settings are simple. I can manually estimate flat shipping rates.'
)
).toBeInTheDocument();

expect(
getByText(
'My shipping settings are complex. I will enter my shipping rates and times manually in Google Merchant Center.'
)
).toBeInTheDocument();

expect(
getByText(
'Automatically sync my store’s shipping settings to Google.'
)
).toBeInTheDocument();
} );
} );
2 changes: 1 addition & 1 deletion js/src/setup-mc/setup-stepper/saved-setup-stepper.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const SavedSetupStepper = ( { savedStep } ) => {
if ( settings?.shipping_rate === null ) {
saveSettings( {
...settings,
shipping_rate: 'automatic',
shipping_rate: 'flat',
shipping_time: 'flat',
} );
}
Expand Down
38 changes: 35 additions & 3 deletions src/API/Site/Controllers/MerchantCenter/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use Automattic\WooCommerce\GoogleListingsAndAds\API\Site\Controllers\BaseOptionsController;
use Automattic\WooCommerce\GoogleListingsAndAds\API\TransportMethods;
use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsInterface;
use Automattic\WooCommerce\GoogleListingsAndAds\Shipping\ShippingZone;
use Automattic\WooCommerce\GoogleListingsAndAds\Proxies\RESTServer;
use WP_REST_Request as Request;

defined( 'ABSPATH' ) || exit;
Expand All @@ -17,6 +19,22 @@
*/
class SettingsController extends BaseOptionsController {

/**
* @var ShippingZone
*/
protected $shipping_zone;

/**
* SettingsController constructor.
*
* @param RESTServer $server
* @param ShippingZone $shipping_zone
*/
public function __construct( RESTServer $server, ShippingZone $shipping_zone ) {
parent::__construct( $server );
$this->shipping_zone = $shipping_zone;
}

/**
* Register rest routes with WordPress.
*/
Expand Down Expand Up @@ -46,9 +64,10 @@ public function register_routes(): void {
*/
protected function get_settings_endpoint_read_callback(): callable {
return function () {
$data = $this->options->get( OptionsInterface::MERCHANT_CENTER, [] );
$schema = $this->get_schema_properties();
$items = [];
$data = $this->options->get( OptionsInterface::MERCHANT_CENTER, [] );
$data['shipping_rates_count'] = $this->shipping_zone->get_shipping_rates_count();
$schema = $this->get_schema_properties();
$items = [];
foreach ( $schema as $key => $property ) {
$items[ $key ] = $data[ $key ] ?? $property['default'] ?? null;
}
Expand All @@ -71,6 +90,9 @@ protected function get_settings_endpoint_edit_callback(): callable {
}

foreach ( $schema as $key => $property ) {
if ( ! in_array( 'edit', $property['context'] ?? [], true ) ) {
Copy link
Contributor Author

@jorgemd24 jorgemd24 Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this so it skips only view properties; otherwise, it would save them as options, like the shipping_rates_count property.

continue;
}
$options[ $key ] = $request->get_param( $key ) ?? $options[ $key ] ?? $property['default'] ?? null;
}

Expand Down Expand Up @@ -178,6 +200,16 @@ protected function get_schema_properties(): array {
'validate_callback' => 'rest_validate_request_arg',
'default' => false,
],
'shipping_rates_count' => [
'type' => 'number',
'description' => __(
'The number of shipping rates in WC ready to be used in the Merchant Center.',
'google-listings-and-ads'
),
'context' => [ 'view' ],
'validate_callback' => 'rest_validate_request_arg',
'default' => 0,
],
];
}

Expand Down
2 changes: 1 addition & 1 deletion src/Internal/DependencyManagement/RESTServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public function provides( string $service ): bool {
* @return void
*/
public function register() {
$this->share( SettingsController::class );
$this->share( SettingsController::class, ShippingZone::class );
$this->share( ConnectionController::class );
$this->share( AdsAccountController::class, AdsAccountService::class );
$this->share( AdsCampaignController::class, AdsCampaign::class );
Expand Down
10 changes: 10 additions & 0 deletions src/Shipping/ShippingZone.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ public function get_shipping_countries(): array {
return array_values( $countries );
}

/**
* Get the number of shipping rates enable in WooCommerce.
*
* @return int
*/
public function get_shipping_rates_count(): int {
$this->parse_shipping_zones();
return count( $this->location_rates ?? [] );
}

/**
* Returns the available shipping rates for a country and its subdivisions.
*
Expand Down
Loading