diff --git a/modules/ppcp-store-sync/src/CartValidation/ShippingValidator.php b/modules/ppcp-store-sync/src/CartValidation/ShippingValidator.php index 2facc5af99..d073b49615 100644 --- a/modules/ppcp-store-sync/src/CartValidation/ShippingValidator.php +++ b/modules/ppcp-store-sync/src/CartValidation/ShippingValidator.php @@ -3,10 +3,11 @@ * Shipping Validator for Agentic Commerce. * * Validates shipping addresses and restrictions according to WooCommerce settings. - * Covers three main scenarios: - * 1. Invalid Shipping Address (completeness, format) - * 2. PO Box Restriction (signature-required items) - * 3. Region Restricted (country not allowed) + * Covers four main scenarios: + * 1. Missing Shipping Address (physical products, no address provided) + * 2. Invalid Shipping Address (completeness, format) + * 3. PO Box Restriction (signature-required items) + * 4. Region Restricted (country not allowed) * * @package WooCommerce\PayPalCommerce\StoreSync\CartValidation */ @@ -17,11 +18,13 @@ use WC_Countries; use WooCommerce\PayPalCommerce\StoreSync\Enums\Priority; +use WooCommerce\PayPalCommerce\StoreSync\Enums\ShippingIssue; use WooCommerce\PayPalCommerce\StoreSync\Helper\ProductManager; use WooCommerce\PayPalCommerce\StoreSync\Schema\PayPalCart; use WooCommerce\PayPalCommerce\StoreSync\Schema\ResolutionOption; use WooCommerce\PayPalCommerce\StoreSync\Validation\InvalidAddress; use WooCommerce\PayPalCommerce\StoreSync\Validation\ShippingUnavailable; +use WooCommerce\PayPalCommerce\StoreSync\Validation\MissingField; use WooCommerce\PayPalCommerce\StoreSync\Schema\Address; use WooCommerce\PayPalCommerce\StoreSync\Schema\CartItem; @@ -35,26 +38,40 @@ public function __construct( ProductManager $product_manager ) { public function validate( PayPalCart $cart ) { $shipping_address = $cart->shipping_address(); - + // Scenario 1: Missing Shipping Address. if ( ! $shipping_address ) { + if ( $this->cart_needs_shipping( $cart ) ) { + return array( + new MissingField( + 'Shipping address is required', + 'Please provide a shipping address to continue.', + 'shipping_address', + '', + array( 'specific_issue' => ShippingIssue::MISSING_SHIPPING_ADDRESS ), + array( + ResolutionOption::provide_shipping_address(), + ) + ), + ); + } return null; } $issues = array(); - // Scenario 1: Invalid Shipping Address. + // Scenario 2: Invalid Shipping Address. $address_issues = $this->validate_address_completeness( $shipping_address ); if ( $address_issues ) { $issues = array_merge( $issues, $address_issues ); } - // Scenario 2: PO Box Restriction. + // Scenario 3: PO Box Restriction. $po_box_issue = $this->validate_po_box_restrictions( $cart, $shipping_address ); if ( $po_box_issue ) { $issues[] = $po_box_issue; } - // Scenario 3: Region Restricted. + // Scenario 4: Region Restricted. $country_issue = $this->validate_country( $shipping_address->country_code() ); if ( $country_issue ) { $issues[] = $country_issue; @@ -63,6 +80,22 @@ public function validate( PayPalCart $cart ) { return $issues ?: null; } + /** + * Checks if any item in the cart requires shipping. + * + * @param PayPalCart $cart The cart to check. + * @return bool True if at least one item needs shipping. + */ + private function cart_needs_shipping( PayPalCart $cart ): bool { + foreach ( $cart->items() as $item ) { + $product = $this->product_manager->find_product( $item ); + if ( $product && $product->needs_shipping() ) { + return true; + } + } + return false; + } + /** * Scenario 1: Validates that the address has all required fields and proper formats. * diff --git a/modules/ppcp-store-sync/src/Schema/ResolutionOption.php b/modules/ppcp-store-sync/src/Schema/ResolutionOption.php index 1c3ec81bf3..defc14cb95 100644 --- a/modules/ppcp-store-sync/src/Schema/ResolutionOption.php +++ b/modules/ppcp-store-sync/src/Schema/ResolutionOption.php @@ -172,6 +172,16 @@ public static function provide_missing_field( string $field_name, string $label ); } + /** + * Factory: Provide shipping address. + * + * @return self + */ + public static function provide_shipping_address(): self { + return self::provide_missing_field( 'shipping_address', 'Add shipping address' )->with( + array( 'metadata' => array( 'priority' => Priority::HIGH ) ) + ); + } /** * Factory: Wait for product restock. *