<?php
declare( strict_types=1 );
namespace Automattic\WooCommerce\GoogleListingsAndAds\Shipping\GoogleAdapter;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidValue;
use Google\Service\ShoppingContent\Price;
use Google\Service\ShoppingContent\RateGroup;
use Google\Service\ShoppingContent\Service as GoogleShippingService;
use Google\Service\ShoppingContent\Value;
defined( 'ABSPATH' ) || exit;
/**
* Class DBShippingSettingsAdapter
*
* @package Automattic\WooCommerce\GoogleListingsAndAds\Shipping
*
* @since 2.1.0
*/
class DBShippingSettingsAdapter extends AbstractShippingSettingsAdapter {
/**
* Parses the already validated input data and maps the provided shipping rates into MC shipping settings.
*
* @param array $data Validated data.
*/
protected function map_gla_data( array $data ): void {
$this->map_db_rates( $data['db_rates'] );
}
/**
* Validates the input array provided to this class.
*
* @param array $data
*
* @throws InvalidValue When the required parameters are not provided, or they are invalid.
*
* @link AbstractShippingSettingsAdapter::mapTypes() The $data input comes from this method.
*/
protected function validate_gla_data( array $data ): void {
parent::validate_gla_data( $data );
if ( empty( $data['db_rates'] ) || ! is_array( $data['db_rates'] ) ) {
throw new InvalidValue( 'The value of "db_rates" must be a non empty associated array of shipping rates.' );
}
}
/**
* Remove the extra data we added to the input array since the MC API doesn't expect them (and it will fail).
*
* @param array $data
*/
protected function unset_gla_data( array &$data ): void {
unset( $data['db_rates'] );
parent::unset_gla_data( $data );
}
/**
* Map the shipping rates stored for each country in DB to MC shipping settings.
*
* @param array[] $db_rates
*
* @return void
*/
protected function map_db_rates( array $db_rates ) {
$services = [];
foreach ( $db_rates as ['country' => $country, 'rate' => $rate, 'options' => $options] ) {
// No negative rates.
if ( $rate < 0 ) {
continue;
}
$service = $this->create_shipping_service( $country, $this->currency, (float) $rate );
if ( isset( $options['free_shipping_threshold'] ) ) {
$minimum_order_value = (float) $options['free_shipping_threshold'];
if ( $rate > 0 ) {
// Add a conditional free-shipping service if the current rate is not free.
$services[] = $this->create_conditional_free_shipping_service( $country, $this->currency, $minimum_order_value );
} else {
// Set the minimum order value if the current rate is free.
$service->setMinimumOrderValue(
new Price(
[
'value' => $minimum_order_value,
'currency' => $this->currency,
]
)
);
}
}
$services[] = $service;
}
$this->setServices( $services );
}
/**
* Create a rate group object for the shopping settings.
*
* @param string $currency
* @param float $rate
*
* @return RateGroup
*/
protected function create_rate_group_object( string $currency, float $rate ): RateGroup {
$price = new Price();
$price->setCurrency( $currency );
$price->setValue( $rate );
$value = new Value();
$value->setFlatRate( $price );
$rate_group = new RateGroup();
$rate_group->setSingleValue( $value );
$name = sprintf(
/* translators: %1 is the shipping rate, %2 is the currency (e.g. USD) */
__( 'Flat rate - %1$s %2$s', 'google-listings-and-ads' ),
$rate,
$currency
);
$rate_group->setName( $name );
return $rate_group;
}
/**
* Create a shipping service object.
*
* @param string $country
* @param string $currency
* @param float $rate
*
* @return GoogleShippingService
*/
protected function create_shipping_service( string $country, string $currency, float $rate ): GoogleShippingService {
$unique = sprintf( '%04x', mt_rand( 0, 0xffff ) );
$service = new GoogleShippingService();
$service->setActive( true );
$service->setDeliveryCountry( $country );
$service->setCurrency( $currency );
$service->setName(
sprintf(
/* translators: %1 is a random 4-digit string, %2 is the rate, %3 is the currency, %4 is the country code */
__( '[%1$s] Google Listings and Ads generated service - %2$s %3$s to %4$s', 'google-listings-and-ads' ),
$unique,
$rate,
$currency,
$country
)
);
$service->setRateGroups( [ $this->create_rate_group_object( $currency, $rate ) ] );
$service->setDeliveryTime( $this->get_delivery_time( $country ) );
return $service;
}
/**
* Create a free shipping service.
*
* @param string $country
* @param string $currency
* @param float $minimum_order_value
*
* @return GoogleShippingService
*/
protected function create_conditional_free_shipping_service( string $country, string $currency, float $minimum_order_value ): GoogleShippingService {
$service = $this->create_shipping_service( $country, $currency, 0 );
// Set the minimum order value to be eligible for free shipping.
$service->setMinimumOrderValue(
new Price(
[
'value' => $minimum_order_value,
'currency' => $currency,
]
)
);
return $service;
}
}