<?php
/**
* Handles the Early Order logic, when we need to create the WC_Order by ourselves.
*
* @package WooCommerce\PayPalCommerce\Button\Helper
*/
declare (strict_types=1);
namespace WooCommerce\PayPalCommerce\Button\Helper;
use RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
/**
* Class EarlyOrderHandler
*/
class EarlyOrderHandler
{
/**
* Whether the merchant is connected to PayPal (onboarding completed).
*
* @var bool
*/
private bool $is_connected;
/**
* The Order Processor.
*
* @var OrderProcessor
*/
private $order_processor;
/**
* The Session Handler.
*
* @var SessionHandler
*/
private $session_handler;
/**
* EarlyOrderHandler constructor.
*
* @param bool $is_connected Whether onboarding was completed.
* @param OrderProcessor $order_processor The Order Processor.
* @param SessionHandler $session_handler The Session Handler.
*/
public function __construct(bool $is_connected, OrderProcessor $order_processor, SessionHandler $session_handler)
{
$this->is_connected = $is_connected;
$this->order_processor = $order_processor;
$this->session_handler = $session_handler;
}
/**
* Whether early orders should be created at all.
*
* @return bool
*/
public function should_create_early_order(): bool
{
return $this->is_connected;
}
//phpcs:disable WordPress.Security.NonceVerification.Recommended
/**
* Tries to determine the current WC Order Id based on the PayPal order
* and the current order in session.
*
* @param int|null $value The initial value.
*
* @return int|null
*/
public function determine_wc_order_id(?int $value = null)
{
if (!isset($_REQUEST['ppcp-resume-order'])) {
return $value;
}
$resume_order_id = (int) WC()->session->get('order_awaiting_payment');
$order = $this->session_handler->order();
if (!$order) {
return $value;
}
$order_id = \false;
foreach ($order->purchase_units() as $purchase_unit) {
if ($purchase_unit->custom_id() === sanitize_text_field(wp_unslash($_REQUEST['ppcp-resume-order']))) {
$order_id = (int) $purchase_unit->custom_id();
}
}
if ($order_id === $resume_order_id) {
$value = $order_id;
}
return $value;
}
//phpcs:enable WordPress.Security.NonceVerification.Recommended
/**
* Registers the necessary checkout actions for a given order.
*
* @param Order $order The PayPal order.
*/
public function register_for_order(Order $order): void
{
add_action('woocommerce_checkout_order_processed', function ($order_id) use ($order) {
try {
$order = $this->configure_session_and_order((int) $order_id, $order);
wp_send_json_success($order->to_array());
} catch (RuntimeException $error) {
wp_send_json_error(array('name' => $error instanceof PayPalApiException ? $error->name() : '', 'message' => $error->getMessage(), 'code' => $error->getCode(), 'details' => $error instanceof PayPalApiException ? $error->details() : array()));
}
});
}
/**
* Configures the session, so we can pick up the order, once we pass through the checkout.
*
* @param int $order_id The WooCommerce order id.
* @param Order $order The PayPal order.
*
* @throws RuntimeException On error.
*/
public function configure_session_and_order(int $order_id, Order $order): Order
{
/**
* Set the order id in our session in order for
* us to resume this order in checkout.
*/
WC()->session->set('order_awaiting_payment', $order_id);
$wc_order = wc_get_order($order_id);
if (!$wc_order instanceof \WC_Order) {
throw new RuntimeException("Invalid WC_Order id {$order_id}.");
}
$wc_order->update_meta_data(PayPalGateway::ORDER_ID_META_KEY, $order->id());
$wc_order->update_meta_data(PayPalGateway::INTENT_META_KEY, $order->intent());
$payment_source = $order->payment_source();
$payment_source_name = $payment_source ? $payment_source->name() : null;
$payer = $order->payer();
if ($payer && $payment_source_name && in_array($payment_source_name, PayPalGateway::PAYMENT_SOURCES_WITH_PAYER_EMAIL, \true)) {
$payer_email = $payer->email_address();
if ($payer_email) {
$wc_order->update_meta_data(PayPalGateway::ORDER_PAYER_EMAIL_META_KEY, $payer_email);
}
}
$wc_order->save_meta_data();
/**
* Patch Order so we have the \WC_Order id added.
*/
$order = $this->order_processor->patch_order($wc_order, $order);
do_action('woocommerce_paypal_payments_woocommerce_order_created', $wc_order, $order);
return $order;
}
}