Newer
Older
TillQliro / Model / OrderManagementStatus / Update / Handler / Shipment.php
@Jonas Jonsson Jonas Jonsson on 2 Apr 2024 9 KB Initial
<?php
/**
 * Copyright © Qliro AB. All rights reserved.
 * See LICENSE.txt for license details.
 */

namespace Qliro\QliroOne\Model\OrderManagementStatus\Update\Handler;

use Magento\Sales\Api\InvoiceRepositoryInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Api\ShipmentRepositoryInterface;
use Magento\Sales\Model\Order\Invoice;
use Magento\Sales\Model\Order\Payment\Transaction\BuilderInterface;
use Qliro\QliroOne\Api\Admin\OrderManagementStatusUpdateHandlerInterface;
use Magento\Sales\Model\Order;
use Qliro\QliroOne\Model\Exception\TerminalException;
use Qliro\QliroOne\Model\Logger\Manager;

class Shipment implements OrderManagementStatusUpdateHandlerInterface
{
    /**
     * @var \Magento\Sales\Api\ShipmentRepositoryInterface
     */
    private $shipmentRepository;

    /**
     * @var \Magento\Sales\Api\OrderRepositoryInterface
     */
    private $orderRepository;

    /**
     * @var \Magento\Sales\Api\InvoiceRepositoryInterface
     */
    private $invoiceRepository;

    /**
     * @var Order\Payment\Transaction\BuilderInterface
     */
    private $transactionBuilder;

    /**
     * @var \Qliro\QliroOne\Model\Logger\Manager
     */
    private $logManager;

    /**
     * Shipment constructor.
     * @param \Magento\Sales\Api\ShipmentRepositoryInterface $shipmentRepository
     * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
     * @param \Magento\Sales\Api\InvoiceRepositoryInterface $invoiceRepository
     * @param \Magento\Sales\Model\Order\Payment\Transaction\BuilderInterface $transactionBuilder
     * @param \Qliro\QliroOne\Model\Logger\Manager $logManager
     */
    public function __construct(
        ShipmentRepositoryInterface $shipmentRepository,
        OrderRepositoryInterface $orderRepository,
        InvoiceRepositoryInterface $invoiceRepository,
        BuilderInterface $transactionBuilder,
        Manager $logManager
    ) {
        $this->shipmentRepository = $shipmentRepository;
        $this->orderRepository = $orderRepository;
        $this->invoiceRepository = $invoiceRepository;
        $this->transactionBuilder = $transactionBuilder;
        $this->logManager = $logManager;
    }

    /**
     * @param \Qliro\QliroOne\Model\Notification\QliroOrderManagementStatus $qliroOrderManagementStatus
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     * @throws \Qliro\QliroOne\Model\Exception\TerminalException
     */
    public function handleSuccess($qliroOrderManagementStatus, $omStatus)
    {

        try {
            $shipment = $this->getShipment($omStatus);
            $order = $shipment->getOrder();
            $payment = $order->getPayment();

            /*
             * Update Order
             */
            if ($order->getState() == Order::STATE_HOLDED) {
                $order->unhold();
                $this->orderRepository->save($order);
            }

            /*
             * Create Invoice
             */
            $invoiceItems = [];
            $shipmentItems = $shipment->getAllItems();

            /** @var \Magento\Sales\Model\Order\Shipment\Item $shipmentItem */
            foreach ($shipmentItems as $shipmentItem) {
                $qty = (int)$shipmentItem->getQty();

                /** @var \Magento\Sales\Model\Order\Item $item */
                $item = $order->getItemById($shipmentItem->getOrderItemId());

                /*
                 * This is the same test for invoice made earlier, as seen in:
                 * \Qliro\QliroOne\Model\QliroOrder\Admin\Builder\ShipmentOrderItemsBuilder::create
                 */
                if ($item->getQtyInvoiced() > 0) {
                    $remaining = $item->getQtyOrdered() - $item->getQtyInvoiced();
                    if ($remaining < $qty) {
                        $qty = $remaining;
                    }
                }

                $invoiceItems[$shipmentItem->getOrderItemId()] = $qty;
            }

            /*
             * Capture online is selected, to make use of all the functions that it runs (payment
             * transactions etc). "qliro_skip_actual_capture" is set to avoid doing the capture
             * inside, since it was already done by the shipment
             */
            if ($order->canInvoice()) {
                $invoice = $order->prepareInvoice($invoiceItems);
                $invoice->setRequestedCaptureCase(Invoice::CAPTURE_ONLINE);
                $payment->setTransactionId($qliroOrderManagementStatus->getPaymentTransactionId());
                $payment->setData(\Qliro\QliroOne\Model\Management::QLIRO_SKIP_ACTUAL_CAPTURE, 1);
                $invoice->register()->pay();
                $this->invoiceRepository->save($invoice);
            } else {
                throw new \Magento\Framework\Exception\LocalizedException(
                    __('Order does not allow to capture')
                );
            }

            $formattedPrice = $order->getBaseCurrency()->formatTxt(
                $qliroOrderManagementStatus->getAmount()
            );

            $order->addStatusHistoryComment(__('Capture of %1 confirmed successful', $formattedPrice));

            $this->orderRepository->save($order);
        } catch (\Exception $exception) {
            $this->logManager->debug(
                $exception,
                [
                    'extra' => [
                        'qliro_order_id' => $qliroOrderManagementStatus->getOrderId(),
                        'shipment_id' => isset($shipment) ? $shipment->getId() : null,
                    ],
                ]
            );
            throw new TerminalException('Could not handle Shipment Success', null, $exception);
        }
    }

    /**
     * @param \Qliro\QliroOne\Model\Notification\QliroOrderManagementStatus $qliroOrderManagementStatus
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     * @throws \Qliro\QliroOne\Model\Exception\TerminalException
     */
    public function handleCancelled($qliroOrderManagementStatus, $omStatus)
    {
        $this->setOnHold($qliroOrderManagementStatus, $omStatus, 'Cancelled');
    }

    /**
     * @param \Qliro\QliroOne\Model\Notification\QliroOrderManagementStatus $qliroOrderManagementStatus
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     * @throws \Qliro\QliroOne\Model\Exception\TerminalException
     */
    public function handleError($qliroOrderManagementStatus, $omStatus)
    {
        $this->setOnHold($qliroOrderManagementStatus, $omStatus, 'Error');
    }

    /**
     * @param \Qliro\QliroOne\Model\Notification\QliroOrderManagementStatus $qliroOrderManagementStatus
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     */
    public function handleInProcess($qliroOrderManagementStatus, $omStatus)
    {
        // Nothing to do
    }

    /**
     * @param \Qliro\QliroOne\Model\Notification\QliroOrderManagementStatus $qliroOrderManagementStatus
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     * @throws \Qliro\QliroOne\Model\Exception\TerminalException
     */
    public function handleOnHold($qliroOrderManagementStatus, $omStatus)
    {
        $this->setOnHold($qliroOrderManagementStatus, $omStatus, 'OnHold');
    }

    /**
     * @param \Qliro\QliroOne\Model\Notification\QliroOrderManagementStatus $qliroOrderManagementStatus
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     * @throws \Qliro\QliroOne\Model\Exception\TerminalException
     */
    public function handleUserInteraction($qliroOrderManagementStatus, $omStatus)
    {
        $this->setOnHold($qliroOrderManagementStatus, $omStatus, 'UserInteraction');
    }

    /**
     * @param \Qliro\QliroOne\Model\Notification\QliroOrderManagementStatus $qliroOrderManagementStatus
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     */
    public function handleCreated($qliroOrderManagementStatus, $omStatus)
    {
        // Nothing to do
    }

    /**
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     * @return \Magento\Sales\Model\Order\Shipment $shipment
     */
    private function getShipment($omStatus)
    {
        $shipment = $this->shipmentRepository->get($omStatus->getRecordId());

        return $shipment;
    }

    /**
     * @param \Qliro\QliroOne\Model\Notification\QliroOrderManagementStatus $qliroOrderManagementStatus
     * @param \Qliro\QliroOne\Model\OrderManagementStatus $omStatus
     * @param string $contextMessage
     * @throws \Qliro\QliroOne\Model\Exception\TerminalException
     */
    private function setOnHold($qliroOrderManagementStatus, $omStatus, $contextMessage)
    {
        try {
            $shipment = $this->getShipment($omStatus);
            $order = $shipment->getOrder();
            $order->hold();

            $order->addStatusHistoryComment(
                __('Order set on hold because Qliro One reported an error with the capture: %1', $contextMessage)
            );

            $this->orderRepository->save($order);
        } catch (\Exception $exception) {
            $this->logManager->critical(
                $exception,
                [
                    'extra' => [
                        'qliro_order_id' => $qliroOrderManagementStatus->getOrderId(),
                    ],
                ]
            );

            throw new TerminalException($exception->getMessage(), $exception->getCode(), $exception);
        }
    }
}