HEX
Server: Apache
System: Linux efa57bbe-abb1-400d-2985-3b056fbc2701.secureserver.net 6.1.147-1.el9.elrepo.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jul 24 12:33:32 EDT 2025 x86_64
User: root (0)
PHP: 8.0.30.4
Disabled: NONE
Upload Files
File: /var/www/wp-content/mu-plugins/vendor/godaddy/mwc-core/src/WooCommerce/Adapters/OrderAdapter.php
<?php

namespace GoDaddy\WordPress\MWC\Core\WooCommerce\Adapters;

use Exception;
use GoDaddy\WordPress\MWC\Common\DataSources\WooCommerce\Adapters\CurrencyAmountAdapter;
use GoDaddy\WordPress\MWC\Common\DataSources\WooCommerce\Adapters\Order\OrderAdapter as CommonOrderAdapter;
use GoDaddy\WordPress\MWC\Common\Exceptions\AdapterException;
use GoDaddy\WordPress\MWC\Common\Helpers\TypeHelper;
use GoDaddy\WordPress\MWC\Common\Models\CurrencyAmount;
use GoDaddy\WordPress\MWC\Common\Models\Orders\Order;
use GoDaddy\WordPress\MWC\Common\Models\Orders\Statuses\CancelledOrderStatus;
use GoDaddy\WordPress\MWC\Common\Models\Orders\Statuses\CheckoutDraftOrderStatus;
use GoDaddy\WordPress\MWC\Common\Models\Orders\Statuses\FailedOrderStatus;
use GoDaddy\WordPress\MWC\Common\Models\Orders\Statuses\RefundedOrderStatus;
use GoDaddy\WordPress\MWC\Common\Traits\CanGetNewInstanceTrait;
use GoDaddy\WordPress\MWC\Core\Features\Commerce\Orders\Providers\DataSources\WooOrderCartIdProvider;
use GoDaddy\WordPress\MWC\Core\WooCommerce\Models\Orders\Order as CoreOrder;
use GoDaddy\WordPress\MWC\Dashboard\Shipping\Adapters\LineItemFulfillmentStatusAdapter;
use GoDaddy\WordPress\MWC\Dashboard\Shipping\Adapters\OrderFulfillmentStatusAdapter;
use WC_Order;
use WC_Order_Item_Product;

/**
 * The Core's Order adapter.
 *
 * Converts between a native core order object and a WooCommerce order object.
 *
 * @method static static getNewInstance(WC_Order $order)
 */
class OrderAdapter extends CommonOrderAdapter
{
    use CanGetNewInstanceTrait;

    /** @var string the Marketplaces channel name order meta key */
    const MARKETPLACES_CHANNEL_NAME_META_KEY = '_marketplaces_channel_name';

    /** @var string the Marketplaces channel type order meta key */
    const MARKETPLACES_CHANNEL_TYPE_META_KEY = '_marketplaces_channel_type';

    /** @var string the Marketplaces channel uuid order meta key */
    const MARKETPLACES_CHANNEL_UUID_META_KEY = '_marketplaces_channel_uuid';

    /** @var string the Marketplaces order status meta key */
    const MARKETPLACES_ORDER_STATUS = '_marketplaces_order_status';

    /** @var string the Marketplaces internal order number order meta key */
    const MARKETPLACES_INTERNAL_ORDER_NUMBER_META_KEY = '_marketplaces_internal_order_number';

    /** @var string the Marketplaces display order number order meta key */
    const MARKETPLACES_DISPLAY_ORDER_NUMBER_META_KEY = '_marketplaces_display_order_number';

    /** @var string the Marketplaces channel order reference meta key */
    const MARKETPLACES_CHANNEL_ORDER_REFERENCE_META_KEY = '_marketplaces_channel_order_reference';

    /** @var string the Marketplaces internal order item id order meta key */
    const MARKETPLACES_INTERNAL_ORDER_ITEM_ID_META_KEY = '_marketplaces_internal_order_item_id';

    /** @var string meta key for the ID referencing the originating channel in the Channels API */
    const ORIGINATING_CHANNEL_ID_META_KEY = '_originating_channel_id';

    /** {@inheritDoc} */
    protected $orderClass = CoreOrder::class;

    /** @var class-string<LineItemAdapter> */
    protected $lineItemAdapterClass = LineItemAdapter::class;

    /** @var class-string<LineItemFulfillmentStatusAdapter> the line item fulfillment status adapter */
    protected $lineItemFulfillmentStatusAdapter = LineItemFulfillmentStatusAdapter::class;

    /** @var class-string<OrderFulfillmentStatusAdapter> the order's fulfillment status adapter */
    protected $orderFulfillmentStatusAdapter = OrderFulfillmentStatusAdapter::class;

    /**
     * Converts a source WooCommerce Order to a core native order.
     *
     * @return CoreOrder
     * @throws AdapterException
     */
    public function convertFromSource() : Order
    {
        /** @var CoreOrder $order */
        $order = parent::convertFromSource();

        $order->setOriginatingChannelId($this->source->get_meta(static::ORIGINATING_CHANNEL_ID_META_KEY));

        $order->setNeedsPayment(TypeHelper::bool($this->source->needs_payment(), false));
        $order->setCheckoutPaymentUrl(TypeHelper::string($this->source->get_checkout_payment_url(), ''));

        $this->convertCustomerNoteFromSource($order);
        $this->convertPaymentDataFromSource($order);
        $this->convertMarketplacesDataFromSource($order);

        // Cart ID
        $this->convertCartIdFromSource($order);

        // fulfillment status
        $this->convertFulfillmentStatusFromSource($order);
        $this->convertLineItemsFulfillmentStatusFromSource($order);

        return $order;
    }

    /**
     * Converts a core native order to a WooCommerce source order object.
     *
     * @param CoreOrder|null $order
     * @return WC_Order
     * @throws AdapterException
     */
    public function convertToSource($order = null) : WC_Order
    {
        if ($order) {
            $this->source->update_meta_data(static::ORIGINATING_CHANNEL_ID_META_KEY, $order->getOriginatingChannelId()); /* @phpstan-ignore-line */
            $this->convertCartIdToSource($order);
            $this->convertCustomerNoteToSource($order);
            $this->convertFulfillmentStatusToSource($order);
        }

        try {
            if ($order) {
                if ($emailAddress = $order->getEmailAddress()) {
                    $this->source->set_billing_email($emailAddress);
                }
            }
        } catch (Exception $exception) {
            throw new AdapterException('Could not adapt native order email address to source order billing email address.', $exception);
        }

        $this->convertMarketplacesDataToSource($this->source, $order);

        parent::convertToSource($order);

        return $this->source;
    }

    /**
     * Sets the cart ID from the given order, if it exists.
     *
     * @param CoreOrder $order
     *
     * @return void
     */
    protected function convertCartIdToSource(CoreOrder $order) : void
    {
        if ($cartId = $order->getCartId()) {
            $this->source = WooOrderCartIdProvider::getNewInstance()->setCartId($this->source, $cartId);
        }
    }

    /**
     * Sets the cart ID from the given order, if it exists.
     *
     * @param CoreOrder $order
     *
     * @return void
     */
    protected function convertCartIdFromSource(CoreOrder $order) : void
    {
        if ($cartId = WooOrderCartIdProvider::getNewInstance()->getCartId($this->source)) {
            $order->setCartId($cartId);
        }
    }

    /**
     * Sets the customer note on the given Order instance if a customer note is available in the source.
     */
    protected function convertCustomerNoteFromSource(CoreOrder $order) : void
    {
        if ($customerNote = $this->source->get_customer_note()) {
            $order->setCustomerNote($customerNote);
        }
    }

    /**
     * Converts payment information from a WC Order object to a core order instance.
     *
     * @param CoreOrder $order
     */
    protected function convertPaymentDataFromSource(CoreOrder $order) : void
    {
        if ($emailAddress = $this->source->get_billing_email()) {
            $order->setEmailAddress($emailAddress);
        }

        if ($this->isSourceOrderCaptured()) {
            $order->setCaptured(true);
        } elseif ($this->isOrderReadyForCapture($order)) {
            $order->setReadyForCapture(true);
        }

        if ($remoteId = $this->source->get_meta('_poynt_order_remoteId')) {
            $order->setRemoteId($remoteId);
        }

        if ($createdVia = $this->source->get_created_via()) {
            $order->setSource((string) $createdVia);
        }

        // Order amounts
        $order->setDiscountAmount($this->convertCurrencyAmountFromSource((float) $this->source->get_total_discount()));
    }

    /**
     * Determines whether the source order can be considered as captured.
     */
    protected function isSourceOrderCaptured() : bool
    {
        if ('yes' === $this->source->get_meta('_mwc_payments_is_captured')) {
            return true;
        }

        return $this->isSourceOrderPaidByAnotherProvider();
    }

    /**
     * Determines whether the source order was paid by provider other than Poynt.
     */
    protected function isSourceOrderPaidByAnotherProvider() : bool
    {
        // we pass 'edit' as the context parameter for get_date_paid() to prevent the `woocommerce_payment_complete_order_status`
        // filter from being triggered for orders that haven't been saved
        // https://godaddy-corp.atlassian.net/browse/MWC-13191
        return 'poynt' !== $this->source->get_meta('_mwc_transaction_provider_name')
            && ! empty($this->source->get_date_paid('edit'))
            && ! empty($this->source->get_transaction_id());
    }

    /**
     * Converts Marketplaces data from a WooCommerce order object to a core order instance.
     *
     * @param CoreOrder $order
     * @return void
     */
    protected function convertMarketplacesDataFromSource(CoreOrder $order) : void
    {
        if ($channelName = $this->source->get_meta(static::MARKETPLACES_CHANNEL_NAME_META_KEY)) {
            $order->setMarketplacesChannelName($channelName);
        }

        if ($channelType = $this->source->get_meta(static::MARKETPLACES_CHANNEL_TYPE_META_KEY)) {
            $order->setMarketplacesChannelType($channelType);
        }

        if ($channelUuid = $this->source->get_meta(static::MARKETPLACES_CHANNEL_UUID_META_KEY)) {
            $order->setMarketplacesChannelUuid($channelUuid);
        }

        if ($orderStatus = $this->source->get_meta(static::MARKETPLACES_ORDER_STATUS)) {
            $order->setMarketplacesStatus($orderStatus);
        }

        if ($displayOrderNumber = $this->source->get_meta(static::MARKETPLACES_DISPLAY_ORDER_NUMBER_META_KEY)) {
            $order->setMarketplacesDisplayOrderNumber($displayOrderNumber);
        }

        if ($internalOrderNumber = $this->source->get_meta(static::MARKETPLACES_INTERNAL_ORDER_NUMBER_META_KEY)) {
            $order->setMarketplacesInternalOrderNumber($internalOrderNumber);
        }

        if ($channelOrderReference = $this->source->get_meta(static::MARKETPLACES_CHANNEL_ORDER_REFERENCE_META_KEY)) {
            $order->setMarketplacesChannelOrderReference($channelOrderReference);
        }
    }

    /**
     * Convert the order's fulfillment status.
     *
     * @param CoreOrder $order
     * @return void
     * @throws AdapterException
     */
    protected function convertFulfillmentStatusFromSource(CoreOrder $order) : void
    {
        try {
            $this->orderFulfillmentStatusAdapter::getNewInstance($this->source)->convertFromSource($order);
        } catch (Exception $exception) {
            throw new AdapterException('Could not adapt fulfillment data.', $exception);
        }
    }

    /**
     * Converts Marketplaces data from a native order object to WooCommerce order metadata.
     *
     * @param WC_Order $wcOrder
     * @param null|CoreOrder $order
     * @return void
     */
    protected function convertMarketplacesDataToSource(WC_Order $wcOrder, ?CoreOrder $order = null) : void
    {
        if (! $order) {
            return;
        }

        $marketplacesMetaData = [
            static::MARKETPLACES_CHANNEL_NAME_META_KEY            => $order->getMarketplacesChannelName(),
            static::MARKETPLACES_CHANNEL_TYPE_META_KEY            => $order->getMarketplacesChannelType(),
            static::MARKETPLACES_CHANNEL_UUID_META_KEY            => $order->getMarketplacesChannelUuid(),
            static::MARKETPLACES_ORDER_STATUS                     => $order->getMarketplacesStatus(),
            static::MARKETPLACES_DISPLAY_ORDER_NUMBER_META_KEY    => $order->getMarketplacesDisplayOrderNumber(),
            static::MARKETPLACES_INTERNAL_ORDER_NUMBER_META_KEY   => $order->getMarketplacesInternalOrderNumber(),
            static::MARKETPLACES_CHANNEL_ORDER_REFERENCE_META_KEY => $order->getMarketplacesChannelOrderReference(),
        ];

        foreach ($marketplacesMetaData as $metaKey => $metaValue) {
            if (null !== $metaValue) {
                $wcOrder->update_meta_data($metaKey, $metaValue);
            }
        }
    }

    /**
     * Determines whether the order is ready to be captured.
     *
     * TODO: remove status classes from mwc-payments package {@wvega 2021-05-31}.
     *
     * @param Order $order
     * @return bool
     */
    protected function isOrderReadyForCapture(Order $order) : bool
    {
        if (! $providerName = $this->source->get_meta('_mwc_transaction_provider_name')) {
            return false;
        }

        if (! $this->source->get_meta('_'.$providerName.'_payment_remoteId')) {
            return false;
        }

        // @TODO: something I don't like about this method: these order status checks imply too much knowledge / dependency on the WC admin. I think the status checks should be done "higher up" near the UI layer, since really these are determining whether to render a WC admin button or not {JS - 2021-10-21}
        // @TODO: something I don't like about this method: 'isOrderReadyForCapture' is assuming an action (capture) rather than returning a state (open authorization). An authorization can be captured or can be voided, so a better method name would probably be something like 'hasOpenAuthorization' or something to that effect, and the calling code can determine what to do with that state {JS - 2021-10-21}
        $orderStatus = $order->getStatus();

        if ($orderStatus instanceof CheckoutDraftOrderStatus) {
            return false;
        }

        if ($orderStatus instanceof CancelledOrderStatus) {
            return false;
        }

        if ($orderStatus instanceof RefundedOrderStatus) {
            return false;
        }

        if ($orderStatus instanceof FailedOrderStatus) {
            return false;
        }

        return true;
    }

    /**
     * Converts an order amount from source.
     *
     * @param float $amount
     * @return CurrencyAmount
     */
    protected function convertCurrencyAmountFromSource(float $amount) : CurrencyAmount
    {
        return (new CurrencyAmountAdapter($amount, (string) $this->source->get_currency()))->convertFromSource();
    }

    /**
     * @param Order $order
     * @return void
     * @throws AdapterException
     */
    protected function convertLineItemsFulfillmentStatusFromSource(Order $order) : void
    {
        try {
            $items = [];
            $lineItems = $order->getLineItems();

            foreach ($lineItems as $lineItem) {
                $sourceLineItem = new WC_Order_Item_Product($lineItem->getId());
                $items[] = $this->lineItemFulfillmentStatusAdapter::getNewInstance($sourceLineItem)->convertFromSource($lineItem);
            }

            $order->setLineItems($items);
        } catch (Exception $exception) {
            throw new AdapterException('Unable to adapt line items.', $exception);
        }
    }

    /**
     * Sets the customer note on the source object.
     *
     * @throws AdapterException
     */
    protected function convertCustomerNoteToSource(CoreOrder $order) : void
    {
        try {
            $this->source->set_customer_note((string) $order->getCustomerNote());
        } catch (Exception $exception) {
            throw AdapterException::getNewInstance('Could not set the customer note on the source order.', $exception);
        }
    }

    /**
     * Sets the fulfillment status of the given order model using the information in the source {@see WC_Order} instance.
     */
    protected function convertFulfillmentStatusToSource(CoreOrder $order) : void
    {
        $this->orderFulfillmentStatusAdapter::getNewInstance($this->source)->convertToSource($order);
    }
}