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; namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WC_Cart; 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\ExperienceContext;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
@ -31,7 +34,8 @@ class ShippingPreferenceFactory {
PurchaseUnit $purchase_unit, PurchaseUnit $purchase_unit,
string $context, string $context,
?WC_Cart $cart = null, ?WC_Cart $cart = null,
string $funding_source = '' string $funding_source = '',
?WC_Order $wc_order = null
): string { ): string {
$contains_physical_goods = $purchase_unit->contains_physical_goods(); $contains_physical_goods = $purchase_unit->contains_physical_goods();
if ( ! $contains_physical_goods ) { if ( ! $contains_physical_goods ) {
@ -39,8 +43,12 @@ class ShippingPreferenceFactory {
} }
$has_shipping = null !== $purchase_unit->shipping(); $has_shipping = null !== $purchase_unit->shipping();
$needs_shipping = $cart && $cart->needs_shipping(); $needs_shipping = ( $wc_order && $this->wc_order_needs_shipping( $wc_order ) ) || ( $cart && $cart->needs_shipping() );
$shipping_address_is_fixed = $needs_shipping && 'checkout' === $context; $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 ) { if ( $shipping_address_is_fixed ) {
// Checkout + no address given? Probably something weird happened, like no form validation? // 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; 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->purchase_unit,
$this->parsed_request_data['context'], $this->parsed_request_data['context'],
WC()->cart, WC()->cart,
$funding_source $funding_source,
$wc_order
); );
$action = in_array( $this->parsed_request_data['context'], $this->pay_now_contexts, true ) ? $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 Mockery;
use WC_Cart; 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\ExperienceContext;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping; use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping;
use WooCommerce\PayPalCommerce\TestCase; use WooCommerce\PayPalCommerce\TestCase;
use function Brain\Monkey\Functions\when;
class ShippingPreferenceFactoryTest extends TestCase class ShippingPreferenceFactoryTest extends TestCase
{ {
@ -18,6 +22,9 @@ class ShippingPreferenceFactoryTest extends TestCase
{ {
parent::setUp(); parent::setUp();
when('wc_shipping_enabled')->justReturn(true);
when('wc_get_shipping_method_count')->justReturn(2);
$this->testee = new ShippingPreferenceFactory(); $this->testee = new ShippingPreferenceFactory();
} }
@ -29,9 +36,10 @@ class ShippingPreferenceFactoryTest extends TestCase
string $context, string $context,
?WC_Cart $cart, ?WC_Cart $cart,
string $funding_source, string $funding_source,
?WC_Order $wc_order,
string $expected_result 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); self::assertEquals($expected_result, $result);
} }
@ -43,6 +51,7 @@ class ShippingPreferenceFactoryTest extends TestCase
'checkout', 'checkout',
$this->createCart(true), $this->createCart(true),
'', '',
null,
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS, ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
]; ];
yield [ yield [
@ -50,6 +59,7 @@ class ShippingPreferenceFactoryTest extends TestCase
'checkout', 'checkout',
$this->createCart(false), $this->createCart(false),
'', '',
null,
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING, ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
]; ];
yield [ yield [
@ -57,6 +67,7 @@ class ShippingPreferenceFactoryTest extends TestCase
'checkout', 'checkout',
$this->createCart(true), $this->createCart(true),
'', '',
null,
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING, ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
]; ];
yield [ yield [
@ -64,6 +75,7 @@ class ShippingPreferenceFactoryTest extends TestCase
'checkout', 'checkout',
$this->createCart(true), $this->createCart(true),
'card', 'card',
null,
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS, ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
]; ];
yield [ yield [
@ -71,34 +83,39 @@ class ShippingPreferenceFactoryTest extends TestCase
'product', 'product',
null, null,
'', '',
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE, null,
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING
]; ];
yield [ yield [
$this->createPurchaseUnit(true, null), $this->createPurchaseUnit(true, null),
'pay-now', 'pay-now',
null, null,
'venmo', 'venmo',
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE, $this->createWcOrder(false),
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING
]; ];
yield [ yield [
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)), $this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
'pay-now', 'pay-now',
null, null,
'venmo', 'venmo',
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE, $this->createWcOrder(true),
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS
]; ];
yield [ yield [
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)), $this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
'pay-now', 'pay-now',
null, null,
'card', 'card',
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS, $this->createWcOrder(true),
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS
]; ];
yield [ yield [
$this->createPurchaseUnit(true, null), $this->createPurchaseUnit(true, null),
'pay-now', 'pay-now',
null, null,
'card', 'card',
$this->createWcOrder(false),
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING, ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
]; ];
} }
@ -115,4 +132,16 @@ class ShippingPreferenceFactoryTest extends TestCase
$cart->shouldReceive('needs_shipping')->andReturn($needsShipping); $cart->shouldReceive('needs_shipping')->andReturn($needsShipping);
return $cart; 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;
}
} }