Skip to content

Commit 96b3377

Browse files
committed
Refactor logic and add comments
1 parent 9a0ba96 commit 96b3377

2 files changed

Lines changed: 74 additions & 12 deletions

File tree

modules/ppcp-api-client/src/Factory/PurchaseUnitFactory.php

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,7 @@ function ( Item $item ): bool {
191191
if ( $this->shipping_needed( ...array_values( $items ) ) && $customer instanceof \WC_Customer ) {
192192
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer, $with_shipping_options );
193193
$shipping_address = $shipping->address();
194-
if (
195-
! $shipping_address ||
196-
2 !== strlen( $shipping_address->country_code() ) ||
197-
! $shipping_address->admin_area_2() ||
198-
( ! $shipping_address->postal_code() && ! $this->country_without_postal_code( $shipping_address->country_code() ) )
199-
) {
194+
if ( ! $shipping_address || ! $this->can_use_shipping_address( $shipping_address ) ) {
200195
$shipping = null;
201196
}
202197
}
@@ -388,11 +383,51 @@ private function sanitize_soft_descriptor( string $soft_descriptor ): string {
388383
* @return bool
389384
*/
390385
private function should_disable_shipping( array $items, ?Address $shipping_address ): bool {
391-
return ! $this->shipping_needed( ...array_values( $items ) ) ||
392-
! $shipping_address ||
393-
empty( $shipping_address->country_code() ) ||
394-
empty( $shipping_address->address_line_1() ) ||
395-
empty( $shipping_address->admin_area_2() ) ||
396-
( ! $shipping_address->postal_code() && ! $this->country_without_postal_code( $shipping_address->country_code() ) );
386+
// No items require physical shipping.
387+
if ( ! $this->shipping_needed( ...array_values( $items ) ) ) {
388+
return true;
389+
}
390+
391+
// Cannot proceed without a shipping address.
392+
if ( ! $shipping_address ) {
393+
return true;
394+
}
395+
396+
return ! $this->can_use_shipping_address( $shipping_address );
397+
}
398+
399+
/**
400+
* Decides whether a shipping address is complete enough to send to PayPal.
401+
*
402+
* PayPal's Orders v2 API rejects incomplete addresses. For virtually every
403+
* country, country_code, address_line_1, admin_area_2 (city), and postal_code
404+
* are required. A small set of countries (see country_without_postal_code())
405+
* have an optional postal code; city is still required there.
406+
*
407+
* @param Address $shipping_address The address to validate.
408+
* @return bool True if the address is usable, false if it should be dropped.
409+
*/
410+
private function can_use_shipping_address( Address $shipping_address ): bool {
411+
// Country code must be a valid 2-letter ISO code.
412+
if ( 2 !== strlen( $shipping_address->country_code() ) ) {
413+
return false;
414+
}
415+
416+
// Street address is required.
417+
if ( empty( $shipping_address->address_line_1() ) ) {
418+
return false;
419+
}
420+
421+
// City is required in virtually every country per PayPal's address rules.
422+
if ( empty( $shipping_address->admin_area_2() ) ) {
423+
return false;
424+
}
425+
426+
// Postal code is required unless the country is on the no-postal-code allowlist.
427+
if ( empty( $shipping_address->postal_code() ) && ! $this->country_without_postal_code( $shipping_address->country_code() ) ) {
428+
return false;
429+
}
430+
431+
return true;
397432
}
398433
}

tests/PHPUnit/ApiClient/Factory/PurchaseUnitFactoryTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,33 @@ public function test_wc_cart_shipping_gets_dropped_when_no_country_code()
290290
$this->assertNull($unit->shipping());
291291
}
292292

293+
public function test_wc_cart_shipping_gets_dropped_when_no_address_line_1()
294+
{
295+
$wc_customer = Mockery::mock(\WC_Customer::class);
296+
expect('WC')->andReturn((object) ['customer' => $wc_customer, 'session' => null]);
297+
298+
$wc_cart = Mockery::mock(\WC_Cart::class);
299+
$amount = Mockery::mock(Amount::class);
300+
$shipping = $this->create_shipping_mock(
301+
$this->create_address_mock('DE', '12345', '', 'Berlin')
302+
);
303+
304+
$shipping_factory = Mockery::mock(ShippingFactory::class);
305+
$shipping_factory->expects('from_wc_customer')->with($wc_customer, false)->andReturn($shipping);
306+
307+
$testee = $this->create_testee(
308+
$this->create_amount_factory_mock($amount, 'from_wc_cart', $wc_cart),
309+
$this->create_item_factory_mock([$this->item], 'from_wc_cart', $wc_cart),
310+
$shipping_factory,
311+
null,
312+
null,
313+
$this->create_payment_level_eligibility_mock('', false)
314+
);
315+
316+
$unit = $testee->from_wc_cart($wc_cart);
317+
$this->assertNull($unit->shipping());
318+
}
319+
293320
public function test_wc_cart_shipping_gets_dropped_when_no_city()
294321
{
295322
$wc_customer = Mockery::mock(\WC_Customer::class);

0 commit comments

Comments
 (0)