Refactor shipping_preference

Extract its determination to a separate class, also remove useless CartRepository and use single PU to avoid confusion.
This commit is contained in:
Alex P 2022-07-05 14:25:55 +03:00
parent 67cdf9be8e
commit fff2570124
20 changed files with 245 additions and 264 deletions

View file

@ -43,13 +43,13 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerReceivableBreakdownFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\SellerStatusFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookEventFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\WebhookFactory;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper;
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
use WooCommerce\PayPalCommerce\ApiClient\Repository\CartRepository;
use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
use WooCommerce\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
@ -221,10 +221,6 @@ return array(
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
return new PartnerReferralsData( $dcc_applies );
},
'api.repository.cart' => static function ( ContainerInterface $container ): CartRepository {
$factory = $container->get( 'api.factory.purchase-unit' );
return new CartRepository( $factory );
},
'api.repository.payee' => static function ( ContainerInterface $container ): PayeeRepository {
$merchant_email = $container->get( 'api.merchant_email' );
$merchant_id = $container->get( 'api.merchant_id' );
@ -298,6 +294,9 @@ return array(
$address_factory = $container->get( 'api.factory.address' );
return new ShippingFactory( $address_factory );
},
'api.factory.shipping-preference' => static function ( ContainerInterface $container ): ShippingPreferenceFactory {
return new ShippingPreferenceFactory();
},
'api.factory.amount' => static function ( ContainerInterface $container ): AmountFactory {
$item_factory = $container->get( 'api.factory.item' );
return new AmountFactory(

View file

@ -163,57 +163,23 @@ class OrderEndpoint {
* Creates an order.
*
* @param PurchaseUnit[] $items The purchase unit items for the order.
* @param string $shipping_preference One of ApplicationContext::SHIPPING_PREFERENCE_ values.
* @param Payer|null $payer The payer off the order.
* @param PaymentToken|null $payment_token The payment token.
* @param PaymentMethod|null $payment_method The payment method.
* @param string $paypal_request_id The paypal request id.
* @param bool $shipping_address_is_fixed Whether the shipping address is changeable or not.
*
* @return Order
* @throws RuntimeException If the request fails.
*/
public function create(
array $items,
string $shipping_preference,
Payer $payer = null,
PaymentToken $payment_token = null,
PaymentMethod $payment_method = null,
string $paypal_request_id = '',
bool $shipping_address_is_fixed = false
string $paypal_request_id = ''
): Order {
$contains_physical_goods = false;
$items = array_filter(
$items,
static function ( $item ) use ( &$contains_physical_goods ): bool {
$is_purchase_unit = is_a( $item, PurchaseUnit::class );
/**
* A purchase unit.
*
* @var PurchaseUnit $item
*/
if ( $is_purchase_unit && $item->contains_physical_goods() ) {
$contains_physical_goods = true;
}
return $is_purchase_unit;
}
);
$shipping_preference = ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
if ( $contains_physical_goods ) {
if ( $shipping_address_is_fixed ) {
// Checkout + no address given? Probably something weird happened, like no form validation?
// Also note that $items currently always seems to be an array with one item.
if ( $this->has_items_without_shipping( $items ) ) {
$shipping_preference = ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
} else {
$shipping_preference = ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS;
}
} else {
$shipping_preference = ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE;
}
}
$bearer = $this->bearer->bearer();
$data = array(
'intent' => ( $this->subscription_helper->cart_contains_subscription() || $this->subscription_helper->current_product_is_subscription() ) ? 'AUTHORIZE' : $this->intent,
@ -598,20 +564,4 @@ class OrderEndpoint {
$new_order = $this->order( $order_to_update->id() );
return $new_order;
}
/**
* Checks if there is at least one item without shipping.
*
* @param PurchaseUnit[] $items The items.
* @return bool Whether items contains shipping or not.
*/
private function has_items_without_shipping( array $items ): bool {
foreach ( $items as $item ) {
if ( ! $item->shipping() ) {
return true;
}
}
return false;
}
}

View file

@ -152,11 +152,15 @@ class PurchaseUnitFactory {
/**
* Creates a PurchaseUnit based off a WooCommerce cart.
*
* @param \WC_Cart $cart The cart.
* @param \WC_Cart|null $cart The cart.
*
* @return PurchaseUnit
*/
public function from_wc_cart( \WC_Cart $cart ): PurchaseUnit {
public function from_wc_cart( ?\WC_Cart $cart = null ): PurchaseUnit {
if ( ! $cart ) {
$cart = WC()->cart ?? new \WC_Cart();
}
$amount = $this->amount_factory->from_wc_cart( $cart );
$items = array_filter(
$this->item_factory->from_wc_cart( $cart ),

View file

@ -0,0 +1,54 @@
<?php
/**
* Returns shipping_preference for the given state.
*
* @package WooCommerce\PayPalCommerce\ApiClient\Factory
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WC_Cart;
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
/**
* Class ShippingPreferenceFactory
*/
class ShippingPreferenceFactory {
/**
* Returns shipping_preference for the given state.
*
* @param PurchaseUnit $purchase_unit Thw PurchaseUnit.
* @param string $context The operation context like 'checkout', 'cart'.
* @param WC_Cart|null $cart The current cart if relevant.
* @return string
*/
public function from_state(
PurchaseUnit $purchase_unit,
string $context,
?WC_Cart $cart = null
): string {
$contains_physical_goods = $purchase_unit->contains_physical_goods();
if ( ! $contains_physical_goods ) {
return ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
}
$has_shipping = null !== $purchase_unit->shipping();
$needs_shipping = $cart && $cart->needs_shipping();
$shipping_address_is_fixed = $needs_shipping && 'checkout' === $context;
if ( $shipping_address_is_fixed ) {
// Checkout + no address given? Probably something weird happened, like no form validation?
if ( ! $has_shipping ) {
return ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING;
}
return ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS;
}
return ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE;
}
}

View file

@ -1,45 +0,0 @@
<?php
/**
* The cart repository returns the purchase units from the current \WC_Cart.
*
* @package WooCommerce\PayPalCommerce\ApiClient\Repository
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Repository;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
/**
* Class CartRepository
*/
class CartRepository implements PurchaseUnitRepositoryInterface {
/**
* The purchase unit factory.
*
* @var PurchaseUnitFactory
*/
private $factory;
/**
* CartRepository constructor.
*
* @param PurchaseUnitFactory $factory The purchase unit factory.
*/
public function __construct( PurchaseUnitFactory $factory ) {
$this->factory = $factory;
}
/**
* Returns all Pur of the WooCommerce cart.
*
* @return PurchaseUnit[]
*/
public function all(): array {
$cart = WC()->cart ?? new \WC_Cart();
return array( $this->factory->from_wc_cart( $cart ) );
}
}

View file

@ -1,26 +0,0 @@
<?php
/**
* The Purchase Unit Repository interface.
*
* @package WooCommerce\PayPalCommerce\ApiClient\Repository
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Repository;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
/**
* Interface PurchaseUnitRepositoryInterface
*/
interface PurchaseUnitRepositoryInterface {
/**
* Returns all purchase units.
*
* @return PurchaseUnit[]
*/
public function all(): array;
}