Merge pull request #3557 from woocommerce/PCP-4974-contact-module-virtual-product-from-block-pages-and-classic-checkout-always-return-default-contact-information-from-pay-pal-window
Some checks failed
CI / PHP 7.4 (push) Has been cancelled
CI / PHP 8.0 (push) Has been cancelled
CI / PHP 8.1 (push) Has been cancelled
CI / PHP 8.2 (push) Has been cancelled
CI / PHP 8.3 (push) Has been cancelled
CI / PHP 8.4 (push) Has been cancelled

Contact module -does not work for virtual products in block pages and classic checkout
This commit is contained in:
Emili Castells 2025-08-08 15:06:21 +02:00 committed by GitHub
commit 2ec6daca38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 109 additions and 83 deletions

View file

@ -17,46 +17,46 @@ class Shipping {
/**
* The name.
*
* @var string
* @var string|null
*/
private $name;
private ?string $name;
/**
* The address.
*
* @var Address
* @var Address|null
*/
private $address;
private ?Address $address;
/**
* Custom contact email address, usually added via the Contact Module.
*/
private ?string $email_address = null;
private ?string $email_address;
/**
* Custom contact phone number, usually added via the Contact Module.
*/
private ?Phone $phone_number = null;
private ?Phone $phone_number;
/**
* Shipping methods.
*
* @var ShippingOption[]
*/
private $options;
private array $options;
/**
* Shipping constructor.
*
* @param string $name The name.
* @param Address $address The address.
* @param string|null $name The name.
* @param Address|null $address The address.
* @param string|null $email_address Contact email.
* @param Phone|null $phone_number Contact phone.
* @param ShippingOption[] $options Shipping methods.
*/
public function __construct(
string $name,
Address $address,
string $name = null,
Address $address = null,
?string $email_address = null,
?Phone $phone_number = null,
array $options = array()
@ -71,18 +71,18 @@ class Shipping {
/**
* Returns the name.
*
* @return string
* @return null|string
*/
public function name(): string {
public function name(): ?string {
return $this->name;
}
/**
* Returns the shipping address.
*
* @return Address
* @return null|Address
*/
public function address(): Address {
public function address(): ?Address {
return $this->address;
}
@ -119,19 +119,26 @@ class Shipping {
* @return array
*/
public function to_array(): array {
$result = array(
'name' => array(
'full_name' => $this->name(),
),
'address' => $this->address()->to_array(),
);
$result = array();
$name = $this->name();
if ( $name ) {
$result['name'] = array(
'full_name' => $name,
);
}
$address = $this->address();
if ( $address ) {
$result['address'] = $address->to_array();
}
$contact_email = $this->email_address();
$contact_phone = $this->phone_number();
if ( $contact_email ) {
$result['email_address'] = $contact_email;
}
$contact_phone = $this->phone_number();
if ( $contact_phone ) {
$result['phone_number'] = $contact_phone->to_array();
}
@ -144,6 +151,7 @@ class Shipping {
$this->options
);
}
return $result;
}
}

View file

@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Helper\PurchaseUnitSanitizer;
use WooCommerce\PayPalCommerce\Webhooks\CustomIds;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Address;
/**
* Class PurchaseUnitFactory
@ -108,21 +109,20 @@ class PurchaseUnitFactory {
* @return PurchaseUnit
*/
public function from_wc_order( \WC_Order $order ): PurchaseUnit {
$amount = $this->amount_factory->from_wc_order( $order );
$items = array_filter(
$amount = $this->amount_factory->from_wc_order( $order );
$items = array_filter(
$this->item_factory->from_wc_order( $order ),
function ( Item $item ): bool {
return $item->unit_amount()->value() >= 0;
}
);
$shipping = $this->shipping_factory->from_wc_order( $order );
if (
! $this->shipping_needed( ... array_values( $items ) ) ||
empty( $shipping->address()->country_code() ) ||
( ! $shipping->address()->postal_code() && ! $this->country_without_postal_code( $shipping->address()->country_code() ) )
) {
$shipping = $this->shipping_factory->from_wc_order( $order );
$shipping_address = $shipping->address();
if ( $this->should_disable_shipping( $items, $shipping_address ) ) {
$shipping = null;
}
$reference_id = 'default';
$description = '';
$custom_id = (string) $order->get_id();
@ -176,10 +176,12 @@ class PurchaseUnitFactory {
$shipping = null;
$customer = \WC()->customer;
if ( $this->shipping_needed( ... array_values( $items ) ) && is_a( $customer, \WC_Customer::class ) ) {
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer, $with_shipping_options );
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer, $with_shipping_options );
$shipping_address = $shipping->address();
if (
2 !== strlen( $shipping->address()->country_code() ) ||
( ! $shipping->address()->postal_code() && ! $this->country_without_postal_code( $shipping->address()->country_code() ) )
! $shipping_address ||
2 !== strlen( $shipping_address->country_code() ) ||
( ! $shipping_address->postal_code() && ! $this->country_without_postal_code( $shipping_address->country_code() ) )
) {
$shipping = null;
}
@ -248,7 +250,7 @@ class PurchaseUnitFactory {
}
$shipping = null;
try {
if ( isset( $data->shipping ) ) {
if ( isset( $data->shipping ) && ! empty( (array) $data->shipping ) ) {
$shipping = $this->shipping_factory->from_paypal_response( $data->shipping );
}
} catch ( RuntimeException $error ) {
@ -337,4 +339,19 @@ class PurchaseUnitFactory {
return substr( $sanitized, 0, 22 ) ?: '';
}
/**
* Determines whether shipping should be disabled for a purchase unit.
*
* @param array $items Purchase unit items.
* @param Address|null $shipping_address The shipping address to validate.
*
* @return bool
*/
private function should_disable_shipping( array $items, ?Address $shipping_address ): bool {
return ! $this->shipping_needed( ... array_values( $items ) ) ||
! $shipping_address ||
empty( $shipping_address->country_code() ) ||
( ! $shipping_address->postal_code() && ! $this->country_without_postal_code( $shipping_address->country_code() ) );
}
}

View file

@ -96,30 +96,25 @@ class ShippingFactory {
* @throws RuntimeException When JSON object is malformed.
*/
public function from_paypal_response( \stdClass $data ): Shipping {
if ( ! isset( $data->name->full_name ) ) {
throw new RuntimeException( 'No name was given for shipping.' );
}
if ( ! isset( $data->address ) ) {
throw new RuntimeException( 'No address was given for shipping.' );
}
$contact_phone = null;
$contact_email = null;
$address = $this->address_factory->from_paypal_response( $data->address );
$name = $data->name->full_name ?? null;
$address = isset( $data->address )
? $this->address_factory->from_paypal_response( $data->address )
: null;
$contact_email = $data->email_address ?? null;
$contact_phone = isset( $data->phone_number->national_number )
? new Phone( $data->phone_number->national_number )
: null;
$options = array_map(
array( $this->shipping_option_factory, 'from_paypal_response' ),
$data->options ?? array()
);
if ( isset( $data->phone_number->national_number ) ) {
$contact_phone = new Phone( $data->phone_number->national_number );
}
if ( isset( $data->email_address ) ) {
$contact_email = $data->email_address;
}
return new Shipping(
$data->name->full_name,
$name,
$address,
$contact_email,
$contact_phone,

View file

@ -265,7 +265,10 @@ export const PayPalComponent = ( {
};
}
const addresses = paypalOrderToWcAddresses( paypalOrder );
let addresses = {};
if ( paypalOrder.purchase_units?.[ 0 ]?.shipping?.address ) {
addresses = paypalOrderToWcAddresses( paypalOrder );
}
return {
type: responseTypes.SUCCESS,

View file

@ -99,31 +99,34 @@ export const handleApprove = async (
order = json.data;
}
const addresses = paypalOrderToWcAddresses( order );
const shippingAddress = order.purchase_units?.[ 0 ]?.shipping?.address;
if ( shippingAddress ) {
const addresses = paypalOrderToWcAddresses( order );
const promises = [
// save address on server
wp.data.dispatch( 'wc/store/cart' ).updateCustomerData( {
billing_address: addresses.billingAddress,
shipping_address: addresses.shippingAddress,
} ),
];
if ( shouldHandleShippingInPayPal() ) {
// set address in UI
promises.push(
wp.data
.dispatch( 'wc/store/cart' )
.setBillingAddress( addresses.billingAddress )
);
if ( shippingData.needsShipping ) {
const promises = [
// save address on server
wp.data.dispatch( 'wc/store/cart' ).updateCustomerData( {
billing_address: addresses.billingAddress,
shipping_address: addresses.shippingAddress,
} ),
];
if ( shouldHandleShippingInPayPal() ) {
// set address in UI
promises.push(
wp.data
.dispatch( 'wc/store/cart' )
.setShippingAddress( addresses.shippingAddress )
.setBillingAddress( addresses.billingAddress )
);
if ( shippingData.needsShipping ) {
promises.push(
wp.data
.dispatch( 'wc/store/cart' )
.setShippingAddress( addresses.shippingAddress )
);
}
}
await Promise.all( promises );
}
await Promise.all( promises );
setPaypalOrder( order );

View file

@ -237,17 +237,18 @@ class WooCommerceOrderCreator {
if ( $shipping ) {
$address = $shipping->address();
$shipping_address = array(
'first_name' => $shipping->name(),
'last_name' => '',
'address_1' => $address->address_line_1(),
'address_2' => $address->address_line_2(),
'city' => $address->admin_area_2(),
'state' => $address->admin_area_1(),
'postcode' => $address->postal_code(),
'country' => $address->country_code(),
);
if ( $address ) {
$shipping_address = array(
'first_name' => $shipping->name(),
'last_name' => '',
'address_1' => $address->address_line_1(),
'address_2' => $address->address_line_2(),
'city' => $address->admin_area_2(),
'state' => $address->admin_area_1(),
'postcode' => $address->postal_code(),
'country' => $address->country_code(),
);
}
$shipping_options = $shipping->options()[0] ?? '';
}

View file

@ -162,7 +162,6 @@ class PurchaseUnitFactoryTest extends TestCase
$shipping = Mockery::mock(Shipping::class);
$shipping
->expects('address')
->times(3)
->andReturn($address);
$shippingFactory = Mockery::mock(ShippingFactory::class);
$shippingFactory