Merge pull request #3616 from woocommerce/PCP-5168-fix-shipping-config

Fix shipping preference
This commit is contained in:
Emili Castells 2025-08-29 10:55:53 +02:00 committed by GitHub
commit df34b7f5c3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 69 additions and 9 deletions

View file

@ -10,6 +10,9 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WC_Cart;
use WC_Order;
use WC_Order_Item_Product;
use WC_Product;
use WooCommerce\PayPalCommerce\ApiClient\Entity\ExperienceContext;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
@ -31,7 +34,8 @@ class ShippingPreferenceFactory {
PurchaseUnit $purchase_unit,
string $context,
?WC_Cart $cart = null,
string $funding_source = ''
string $funding_source = '',
?WC_Order $wc_order = null
): string {
$contains_physical_goods = $purchase_unit->contains_physical_goods();
if ( ! $contains_physical_goods ) {
@ -39,8 +43,12 @@ class ShippingPreferenceFactory {
}
$has_shipping = null !== $purchase_unit->shipping();
$needs_shipping = $cart && $cart->needs_shipping();
$shipping_address_is_fixed = $needs_shipping && 'checkout' === $context;
$needs_shipping = ( $wc_order && $this->wc_order_needs_shipping( $wc_order ) ) || ( $cart && $cart->needs_shipping() );
$shipping_address_is_fixed = $needs_shipping && in_array( $context, array( 'checkout', 'pay-now' ), true );
if ( ! $needs_shipping ) {
return ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING;
}
if ( $shipping_address_is_fixed ) {
// Checkout + no address given? Probably something weird happened, like no form validation?
@ -61,4 +69,26 @@ class ShippingPreferenceFactory {
return ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE;
}
protected function wc_order_needs_shipping( WC_Order $wc_order ): bool {
// WC 9.9.0+.
if ( method_exists( $wc_order, 'needs_shipping' ) ) {
return $wc_order->needs_shipping();
}
if ( ! wc_shipping_enabled() || wc_get_shipping_method_count( true ) === 0 ) {
return false;
}
foreach ( $wc_order->get_items() as $item ) {
if ( $item instanceof WC_Order_Item_Product ) {
$product = $item->get_product();
if ( $product instanceof WC_Product && $product->needs_shipping() ) {
return true;
}
}
}
return false;
}
}

View file

@ -440,7 +440,8 @@ class CreateOrderEndpoint implements EndpointInterface {
$this->purchase_unit,
$this->parsed_request_data['context'],
WC()->cart,
$funding_source
$funding_source,
$wc_order
);
$action = in_array( $this->parsed_request_data['context'], $this->pay_now_contexts, true ) ?

View file

@ -5,10 +5,14 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use Mockery;
use WC_Cart;
use WC_Order;
use WC_Order_Item_Product;
use WC_Product;
use WooCommerce\PayPalCommerce\ApiClient\Entity\ExperienceContext;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping;
use WooCommerce\PayPalCommerce\TestCase;
use function Brain\Monkey\Functions\when;
class ShippingPreferenceFactoryTest extends TestCase
{
@ -18,6 +22,9 @@ class ShippingPreferenceFactoryTest extends TestCase
{
parent::setUp();
when('wc_shipping_enabled')->justReturn(true);
when('wc_get_shipping_method_count')->justReturn(2);
$this->testee = new ShippingPreferenceFactory();
}
@ -29,9 +36,10 @@ class ShippingPreferenceFactoryTest extends TestCase
string $context,
?WC_Cart $cart,
string $funding_source,
?WC_Order $wc_order,
string $expected_result
) {
$result = $this->testee->from_state($purchase_unit, $context, $cart, $funding_source);
$result = $this->testee->from_state($purchase_unit, $context, $cart, $funding_source, $wc_order);
self::assertEquals($expected_result, $result);
}
@ -43,6 +51,7 @@ class ShippingPreferenceFactoryTest extends TestCase
'checkout',
$this->createCart(true),
'',
null,
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
];
yield [
@ -50,6 +59,7 @@ class ShippingPreferenceFactoryTest extends TestCase
'checkout',
$this->createCart(false),
'',
null,
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
];
yield [
@ -57,6 +67,7 @@ class ShippingPreferenceFactoryTest extends TestCase
'checkout',
$this->createCart(true),
'',
null,
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
];
yield [
@ -64,6 +75,7 @@ class ShippingPreferenceFactoryTest extends TestCase
'checkout',
$this->createCart(true),
'card',
null,
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
];
yield [
@ -71,34 +83,39 @@ class ShippingPreferenceFactoryTest extends TestCase
'product',
null,
'',
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
null,
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING
];
yield [
$this->createPurchaseUnit(true, null),
'pay-now',
null,
'venmo',
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
$this->createWcOrder(false),
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING
];
yield [
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
'pay-now',
null,
'venmo',
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
$this->createWcOrder(true),
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS
];
yield [
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
'pay-now',
null,
'card',
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
$this->createWcOrder(true),
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS
];
yield [
$this->createPurchaseUnit(true, null),
'pay-now',
null,
'card',
$this->createWcOrder(false),
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
];
}
@ -115,4 +132,16 @@ class ShippingPreferenceFactoryTest extends TestCase
$cart->shouldReceive('needs_shipping')->andReturn($needsShipping);
return $cart;
}
private function createWcOrder(bool $needsShipping): WC_Order {
$product = Mockery::mock(WC_Product::class);
$product->shouldReceive('needs_shipping')->andReturn($needsShipping);
$item = Mockery::mock(WC_Order_Item_Product::class);
$item->shouldReceive('get_product')->andReturn($product);
$wcOrder = Mockery::mock(WC_Order::class);
$wcOrder->shouldReceive('get_items')->andReturn([$item]);
return $wcOrder;
}
}