Skip to content
Code-Schnipsel Gruppen Projekte
OrderProcess.php 48,1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Henning Leutz's avatar
    Henning Leutz committed
    <?php
    
    /**
     * This file contains QUI\ERP\Order\OrderProcess
     */
    
    namespace QUI\ERP\Order;
    
    use QUI;
    
    use QUI\ERP\Order\Controls\AbstractOrderingStep;
    
    use QUI\ERP\Order\Controls\OrderProcess\Processing;
    
    use QUI\ERP\Order\OrderProcess\OrderProcessMessageHandlerInterface;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use QUI\ERP\Order\Utils\OrderProcessSteps;
    
    use QUI\ERP\Order\Controls\OrderProcess\Finish as FinishControl;
    use QUI\Exception;
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    use function array_filter;
    use function array_keys;
    use function array_search;
    use function array_values;
    use function call_user_func;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function class_exists;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function count;
    use function current;
    use function dirname;
    use function end;
    use function floor;
    use function get_class;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function is_a;
    use function json_decode;
    use function json_encode;
    use function key;
    use function method_exists;
    use function reset;
    use function trim;
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    /**
    
     * Class OrderingProcess
    
     *
     * This is the ordering process
    
     * Coordinates the order process, (basket -> address -> delivery -> payment -> invoice)
    
    Henning Leutz's avatar
    Henning Leutz committed
     *
    
     * @package QUI\ERP\Order\Basket
    
     *
     * @event getBody [this]
     * @event getBodyBegin [this]
     * @event onSend [this]
     * @event onSendBegin [this]
    
    Henning Leutz's avatar
    Henning Leutz committed
     */
    
    class OrderProcess extends QUI\Control
    
    Henning Leutz's avatar
    Henning Leutz committed
    {
    
        const MESSAGES_SESSION_KEY = 'quiqqer_order_orderprocess_messages';
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
    
        protected ?AbstractOrder $Order = null;
    
        protected ?Basket\Basket $Basket = null;
    
        /**
         * @var null|AbstractOrderProcessProvider
         */
    
        protected ?AbstractOrderProcessProvider $ProcessingProvider = null;
    
        /**
         * List of order process steps
         *
         * @var array
         */
    
    
        /**
         * @var QUI\Events\Event
         */
    
        public QUI\Events\Event $Events;
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
    
         * @param array $attributes
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        public function __construct(array $attributes = [])
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
    
            $this->setAttributes([
    
                'Site' => false,
                'data-qui' => 'package/quiqqer/order/bin/frontend/controls/OrderProcess',
                'orderHash' => false,
                'basket' => true, // import basket articles to the order, use the basket
    
    Henning Leutz's avatar
    Henning Leutz committed
                'basketEditable' => true,
    
                'backToShopUrl' => false
    
            parent::__construct($attributes);
    
    
            if (isset($attributes['Order']) && $attributes['Order'] instanceof AbstractOrder) {
                $this->Order = $attributes['Order'];
            }
    
            $this->addCSSFile(dirname(__FILE__) . '/Controls/OrderProcess.css');
    
            $this->Events = new QUI\Events\Event();
    
            $User = QUI::getUserBySession();
    
            $isNobody = QUI::getUsers()->isNobodyUser($User);
    
    
            $step = $this->getAttribute('step');
    
            $customerUUID = $Order->getCustomer()->getUUID();
            $userUUID = $User->getUUID();
    
            if ($customerUUID !== $userUUID && !QUI::getUsers()->isSystemUser($User)) {
    
                throw new QUI\Permissions\Exception([
                    'quiqqer/order',
                    'exception.no.permission.for.this.order'
                ]);
            }
    
    
            if ($Order->isSuccessful()) {
    
                $this->setAttribute('orderHash', $Order->getUUID());
    
    Henning Leutz's avatar
    Henning Leutz committed
                $LastStep = end($steps);
    
    
                $this->setAttribute('step', $LastStep->getName());
    
                $this->setAttribute('orderHash', $Order->getUUID());
    
            // basket into the order
            $Basket = $this->getBasket();
    
            if (!$this->getAttribute('orderHash') && $this->getAttribute('basket')) {
    
            $this->setAttribute('basketId', $Basket->getId());
    
            $this->setAttribute('orderHash', $Order->getUUID());
    
            // set order currency
            $UserCurrency = QUI\ERP\Defaults::getUserCurrency();
    
            if ($UserCurrency && $UserCurrency->getCode() !== $Order->getCurrency()->getCode()) {
                $Order->setCurrency($UserCurrency);
    
                $Order->update();
    
    Henning Leutz's avatar
    Henning Leutz committed
            // order is successful, so no other step must be shown
    
            if ($Order && $Order->isSuccessful()) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $LastStep = end($steps);
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->setAttribute('step', $LastStep->getName());
    
                $this->setAttribute('orderHash', $Order->getUUID());
    
    Henning Leutz's avatar
    Henning Leutz committed
                return;
            }
    
    
            if (!$step && isset($_REQUEST['step'])) {
                $step = $_REQUEST['step'];
                $this->setAttribute('step', $step);
            }
    
            if (!$step && isset($_REQUEST['current'])) {
                $step = $_REQUEST['current'];
                $this->setAttribute('step', $step);
            }
    
            if (!$step && isset($_REQUEST['current'])) {
                $step = $_REQUEST['current'];
                $this->setAttribute('step', $step);
            }
    
    
            if (isset($_GET['checkout']) && $_GET['checkout'] == 1) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $keys = array_keys($steps);
    
                $this->setAttribute('step', $keys[1]);
                $step = $keys[1];
            }
    
    
            // consider processing step - processing step is ok
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            if ($Processing->getName() === $step) {
    
                $this->setAttribute('orderHash', $Order->getUUID());
    
    Henning Leutz's avatar
    Henning Leutz committed
                return;
            }
    
    
            if (!$step || !isset($steps[$step])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                reset($steps);
                $this->setAttribute('step', key($steps));
    
    
            QUI::getEvents()->fireEvent('orderProcess', [$this]);
    
        }
    
        /**
         * Checks the submit status
         * Must the previous step be saved?
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
    
         * In this case, it is the step the user took when he clicked next.
         * Or the user clicked a submit button in the step
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @throws Exception
    
        protected function checkSubmission(): void
    
        {
            if (!isset($_REQUEST['current'])) {
                return;
            }
    
            $preStep = $_REQUEST['current'];
            $PreStep = $this->getStepByName($preStep);
    
            if (!$PreStep) {
                return;
            }
    
    
            try {
                $PreStep->save();
            } catch (QUI\Exception $Exception) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                QUI\System\Log::writeDebugException($Exception);
    
    Henning Leutz's avatar
    Henning Leutz committed
        }
    
        protected function checkSuccessfulStatus(): void
    
        {
            try {
                $Current = $this->getCurrentStep();
    
            } catch (QUI\Exception) {
    
            if (
    
                !($Current instanceof FinishControl)
    
                && !($Current instanceof Controls\OrderProcess\Processing)
            ) {
    
                return;
            }
    
            try {
                $Payment = $this->getOrder()->getPayment();
    
    
                if ($Payment && $Payment->isSuccessful($this->getOrder()->getUUID())) {
    
                    $this->getOrder()->setSuccessfulStatus();
                }
            } catch (QUI\Exception $Exception) {
                QUI\System\Log::writeDebugException($Exception);
            }
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
        protected function send(): void
    
            $this->Events->fireEvent('sendBegin', [$this]);
    
            QUI::getEvents()->fireEvent('onQuiqqerOrderProcessSendBegin', [$this]);
    
            $steps = $this->getSteps();
    
            $providers = QUI\ERP\Order\Handler::getInstance()->getOrderProcessProvider();
    
    Henning Leutz's avatar
    Henning Leutz committed
            // #locale quiqqer/order#158
            if (class_exists('QUI\ERP\Products\Handler\Products')) {
                QUI\ERP\Products\Handler\Products::setLocale(QUI::getLocale());
            }
    
    
            // check all previous steps
    
            // is one invalid, go to them
    
            foreach ($steps as $Step) {
    
                /* @var $Step AbstractOrderingStep */
    
                if (
                    $Step->getName() === 'Basket'
    
    Henning Leutz's avatar
    Henning Leutz committed
                    || $Step->getName() === 'Checkout'
    
                    || $Step->getName() === 'Finish'
                ) {
    
                try {
                    $Step->validate();
    
                } catch (Exception) {
    
                    $this->setAttribute('current', $Step->getName());
                }
    
    
            QUI::getEvents()->fireEvent('orderStart', [$this]);
    
            // Gehe die verschiedenen Processing Provider durch
    
    Henning Leutz's avatar
    Henning Leutz committed
            $OrderInProcess = $this->getOrder();
    
            $success = [];
    
            $failedPaymentProcedure = Settings::getInstance()->get('order', 'failedPaymentProcedure');
    
    
            foreach ($providers as $Provider) {
                /* @var $Provider AbstractOrderProcessProvider */
    
    Henning Leutz's avatar
    Henning Leutz committed
                $status = $Provider->onOrderStart($OrderInProcess);
    
    
                if ($status === AbstractOrderProcessProvider::PROCESSING_STATUS_PROCESSING) {
    
                    $this->ProcessingProvider = $Provider;
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
                    if ($failedPaymentProcedure !== 'execute') {
                        return;
                    }
    
                }
    
                if ($status === AbstractOrderProcessProvider::PROCESSING_STATUS_ABORT) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $Provider->onOrderAbort($OrderInProcess);
    
    Henning Leutz's avatar
    Henning Leutz committed
                $success[] = $Provider->onOrderSuccess($OrderInProcess);
    
            QUI::getEvents()->fireEvent('onQuiqqerOrderProcessSendCreateOrder', [$this]);
    
    
            if ($OrderInProcess instanceof OrderInProcess) {
                $Order = $OrderInProcess->createOrder();
                $OrderInProcess->delete();
    
                $this->Order = $Order;
            } else {
                $this->Order = $OrderInProcess;
            }
    
            $this->setAttribute('orderHash', $this->Order->getUUID());
    
            $this->setAttribute('current', 'Finish');
            $this->setAttribute('step', 'Finish');
    
    Henning Leutz's avatar
    Henning Leutz committed
            // set all to successful
            $this->cleanup();
    
    
            $this->Events->fireEvent('send', [$this, $this->Order]);
    
            QUI::getEvents()->fireEvent('onQuiqqerOrderProcessSend', [$this]);
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Cleanup stuff, look if smth is not needed anymore
         */
    
        protected function cleanup(): void
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            // set all to successful
            if (!$this->Order->isSuccessful()) {
                return;
            }
    
    
            // if temp order exist, and a normal order kill it
    
    Henning Leutz's avatar
    Henning Leutz committed
            try {
    
                $ProcessOrder = Handler::getInstance()->getOrderInProcessByHash(
    
                    $this->Order->getUUID()
    
                );
    
                $Order = Handler::getInstance()->getOrderByHash(
    
                    $ProcessOrder->getUUID()
    
                );
    
                if ($Order instanceof Order) {
                    $ProcessOrder->delete();
                }
    
                $this->Order = $Order;
    
    Henning Leutz's avatar
    Henning Leutz committed
            } catch (QUI\Exception $Exception) {
                QUI\System\Log::writeDebugException($Exception);
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($this->Basket && method_exists($this->Basket, 'successful')) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->Basket->successful();
                $this->Basket->save();
            } else {
                try {
    
                    $Basket = Handler::getInstance()->getBasketByHash($this->Order->getUUID());
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $Basket->successful();
                    $Basket->save();
                } catch (QUI\Exception $Exception) {
                    QUI\System\Log::writeDebugException($Exception);
                }
            }
        }
    
    
         * Execute the payable step
         *
         * @return bool|string
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
    
         * @throws QUI\Exception|\Exception
    
        protected function executePayableStatus(): bool | string
    
    Henning Leutz's avatar
    Henning Leutz committed
            $template = dirname(__FILE__) . '/Controls/OrderProcess.html';
    
            $Engine = QUI::getTemplateManager()->getEngine();
    
            try {
                $this->send();
    
                // processing step
                // eq: payment gateway
                if ($this->ProcessingProvider !== null) {
    
                    $ProcessingStep->setProcessingProvider($this->ProcessingProvider);
                    $ProcessingStep->setAttribute('Order', $this->getOrder());
    
    
                    $this->setAttribute('step', $ProcessingStep->getName());
    
                    // shows payment changing, if allowed
                    $changePayment = false;
    
                    $Payment = $this->getOrder()->getPayment();
    
    
                    if (Settings::getInstance()->get('paymentChangeable', $Payment->getId())) {
                        $changePayment = true;
                    }
    
    
                    $Engine->assign([
    
                        'listWidth' => floor(100 / count($this->getSteps())),
                        'this' => $this,
                        'error' => false,
                        'next' => false,
                        'previous' => false,
                        'payableToOrder' => false,
                        'changePayment' => $changePayment,
                        'steps' => $this->getSteps(),
                        'CurrentStep' => $ProcessingStep,
    
                        'currentStepContent' => QUI\ControlUtils::parse($ProcessingStep),
    
                        'Site' => $this->getSite(),
                        'Order' => $this->getOrder(),
                        'hash' => $this->getStepHash(),
                        'backToShopUrl' => $this->getBackToShopUrl()
    
    Henning Leutz's avatar
    Henning Leutz committed
                    return QUI\Output::getInstance()->parse($Engine->fetch($template));
    
                $Engine->assign([
    
                    'listWidth' => floor(100 / count($this->getSteps())),
                    'this' => $this,
                    'error' => false,
                    'next' => false,
                    'previous' => false,
                    'payableToOrder' => false,
                    'steps' => $this->getSteps(),
                    'CurrentStep' => $this->getCurrentStep(),
    
                    'currentStepContent' => QUI\ControlUtils::parse($this->getCurrentStep()),
    
                    'Site' => $this->getSite(),
                    'Order' => $this->getOrder(),
                    'hash' => $this->getStepHash(),
                    'backToShopUrl' => $this->getBackToShopUrl()
    
    Henning Leutz's avatar
    Henning Leutz committed
                return QUI\Output::getInstance()->parse($Engine->fetch($template));
    
            } catch (QUI\Exception $Exception) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                QUI\System\Log::writeDebugException($Exception);
    
         * @return string
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws QUi\Exception
    
        public function getBody(): string
    
            $this->Events->fireEvent('getBodyBegin', [$this]);
    
            QUI::getEvents()->fireEvent('quiqqerOrderOrderProcessGetBodyBegin', [$this]);
    
            $this->setAttribute(
                'data-qui-option-basketeditable',
                $this->getAttribute('basketEditable') ? 1 : 0
            );
    
    
            $User = QUI::getUserBySession();
    
            $isNobody = QUI::getUsers()->isNobodyUser($User);
    
    Henning Leutz's avatar
    Henning Leutz committed
            $template = dirname(__FILE__) . '/Controls/OrderProcess.html';
    
            $Engine = QUI::getTemplateManager()->getEngine();
    
            if ($isNobody) {
    
                $guestOrderInstalled = QUI::getPackageManager()->isInstalled('quiqqer/order-guestorder');
                $GuestOrder = null;
                $nobodyIntroTitle = '';
                $nobodyIntroDesc = '';
                $Site = $this->getSite();
    
    
                if (
                    class_exists('QUI\ERP\Order\Guest\GuestOrder')
                    && class_exists('QUI\ERP\Order\Guest\Controls\GuestOrderButton')
                    && $guestOrderInstalled
                    && QUI\ERP\Order\Guest\GuestOrder::isActive()
                ) {
    
                    $GuestOrder = new QUI\ERP\Order\Guest\Controls\GuestOrderButton();
    
                    if ($Site->getAttribute('quiqqer.order.nobody.intro.title')) {
                        $nobodyIntroTitle = $Site->getAttribute('quiqqer.order.nobody.intro.title');
                    }
    
                    if ($Site->getAttribute('quiqqer.order.nobody.intro.desc')) {
                        $nobodyIntroDesc = $Site->getAttribute('quiqqer.order.nobody.intro.desc');
                    }
                }
    
                $Request = QUI::getRequest();
                $url = $Request->getRequestUri();
    
                $activeEntry = match (true) {
                    str_contains($url, '?open=login') => 'login',
                    str_contains($url, '?open=signup') => 'signup',
                    default => 'login'
                };
    
    
                if (
                    $guestOrderInstalled
                    && class_exists('QUI\ERP\Order\Guest\GuestOrder')
                    && str_contains($url, '?open=guest')
                    && QUI\ERP\Order\Guest\GuestOrder::isActive()
                ) {
    
                    $activeEntry = 'guest';
                }
    
    
                $Engine->assign([
    
                    'Registration' => new Controls\Checkout\Registration([
                        'autofill' => false
                    ]),
    
                    'Login' => new Controls\Checkout\Login(),
                    'guestOrderInstalled' => $guestOrderInstalled,
                    'GuestOrder' => $GuestOrder,
                    'activeEntry' => $activeEntry,
                    'nobodyIntroTitle' => $nobodyIntroTitle,
                    'nobodyIntroDesc' => $nobodyIntroDesc
    
                ]);
    
                return $Engine->fetch(
    
    Henning Leutz's avatar
    Henning Leutz committed
                    dirname(__FILE__) . '/Controls/OrderProcess.Nobody.html'
    
    Henning Leutz's avatar
    Henning Leutz committed
            // check if processing step is needed
            $processing = $this->checkProcessing();
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (!empty($processing)) {
    
                QUI::getEvents()->fireEvent('quiqqerOrderProcessingStart', [$this]);
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                return $processing;
    
            $steps = $this->getSteps();
    
    Henning Leutz's avatar
    Henning Leutz committed
            $LastStep = end($steps);
    
            $this->checkSubmission();
    
            // check if order is finished
    
            $Order = $this->getOrder();
    
            if ($Order && $Order->isSuccessful()) {
    
                if ($Order instanceof OrderInProcess && !$Order->getOrderId()) {
    
                    $this->send();
                    $Order = $this->Order;
    
                $this->setAttribute('step', $LastStep->getName());
    
                $this->setAttribute('orderHash', $Order->getUUID());
    
            $Current = $this->getCurrentStep();
    
    
            // check all previous steps
    
    Henning Leutz's avatar
    Henning Leutz committed
            // is one invalid, go to them
    
            foreach ($steps as $name => $Step) {
                if ($name === $Current->getName()) {
                    break;
                }
    
                /* @var $Step AbstractOrderingStep */
                if ($Step->isValid() === false) {
                    $Current = $Step;
                    break;
                }
            }
    
    
            $error = false;
            $next = $this->getNextStepName($Current);
    
            $previous = $this->getPreviousStepName();
    
            $payableToOrder = false;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            /* @var $Checkout AbstractOrderingStep */
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Checkout = current(
                array_filter($this->getSteps(), function ($Step) {
                    /* @var $Step AbstractOrderingStep */
                    return $Step->getType() === Controls\OrderProcess\Checkout::class;
                })
            );
    
            if ($Current->showNext() === false) {
                $next = false;
            }
    
    
            if (
                $previous === ''
    
                || $Current->getName() === $this->getFirstStep()->getName()
            ) {
                $previous = false;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($Current->getName() === $Checkout->getName()) {
    
                $next = false;
    
                $payableToOrder = true;
            }
    
            try {
                $Current->validate();
    
    
                $this->Events->fireEvent('validate', [$this]);
                QUI::getEvents()->fireEvent('quiqqerOrderOrderProcessValidate', [$this]);
    
            } catch (QUI\ERP\Order\Exception $Exception) {
                $error = $Exception->getMessage();
    
                if (get_class($Current) === FinishControl::class) {
    
                    $Current = $this->getPreviousStep();
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                    if (method_exists($Current, 'forceSave')) {
    
                        $Current->forceSave();
                    }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                    try {
                        $Current->validate();
                        $error = false;
                    } catch (\Exception $Exception) {
    
                        $error = $Exception->getMessage();
    
    Henning Leutz's avatar
    Henning Leutz committed
                        $Current = $this->getPreviousStep();
                    }
    
    
                // if step is the same as the current step, then we need an error message
                // if step is not the same as the current step, then we need not an error message
                if ($this->getAttribute('step') === $Current->getName()) {
                    $error = false;
                }
    
            } catch (\Exception $Exception) {
                QUI\System\Log::writeException($Exception);
                $Current = $this->getPreviousStep();
    
            $Project = $this->getSite()->getProject();
    
    
            $this->setAttribute('step', $Current->getName());
    
            $this->setAttribute('data-url', Utils\Utils::getOrderProcess($Project)->getUrlRewritten());
    
            if ($Current instanceof FinishControl) {
    
                $next = false;
    
    Henning Leutz's avatar
    Henning Leutz committed
            $frontendMessages = [];
            $FrontendMessages = $Order->getFrontendMessages();
    
            if (!$FrontendMessages->isEmpty()) {
                $frontendMessages = $FrontendMessages->toArray();
                $Order->clearFrontendMessages();
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            // #locale quiqqer/order#158
            if (class_exists('QUI\ERP\Products\Handler\Products')) {
                QUI\ERP\Products\Handler\Products::setLocale(QUI::getLocale());
            }
    
    
            $Engine->assign([
    
                'listWidth' => floor(100 / count($this->getSteps())),
                'this' => $this,
                'error' => $error,
                'next' => $next,
                'previous' => $previous,
                'payableToOrder' => $payableToOrder,
                'steps' => $this->getSteps(),
                'CurrentStep' => $Current,
    
                'currentStepContent' => QUI\ControlUtils::parse($Current),
    
                'Site' => $this->getSite(),
                'Order' => $this->getOrder(),
                'hash' => $this->getStepHash(),
                'messages' => $this->getStepMessages(get_class($Current)),
                'frontendMessages' => $frontendMessages,
                'backToShopUrl' => $this->getBackToShopUrl()
    
            $this->Events->fireEvent('getBody', [$this]);
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            return QUI\Output::getInstance()->parse($Engine->fetch($template));
        }
    
        /**
         * checks if the order is in the payment process
         *if yes, they try to make the payment step
         *
         * @return bool|string
         *
         * @throws Exception
         * @throws QUI\Exception
         */
    
        protected function checkProcessing(): bool | string
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            $Current = $this->getCurrentStep();
    
            $Order = $this->getOrder();
    
    
            if (!$Order) {
                return false;
            }
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
    Patrick Müller's avatar
    Patrick Müller committed
            if (!$Order->getPayment()) {
    
                return false;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $checkedTermsAndConditions = QUI::getSession()->get(
    
                'termsAndConditions-' . $Order->getUUID()
    
    Henning Leutz's avatar
    Henning Leutz committed
            );
    
    
            if ($Order->isSuccessful() || $Order instanceof Order) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $checkedTermsAndConditions = true;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (!$checkedTermsAndConditions) {
                return false;
            }
    
            /* @var $Checkout AbstractOrderingStep */
            /* @var $Finish AbstractOrderingStep */
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Checkout = current(
                array_filter($this->getSteps(), function ($Step) {
                    /* @var $Step AbstractOrderingStep */
                    return $Step->getType() === Controls\OrderProcess\Checkout::class;
                })
            );
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Finish = current(
                array_filter($this->getSteps(), function ($Step) {
                    /* @var $Step AbstractOrderingStep */
    
                    return $Step->getType() === FinishControl::class;
    
            $render = function () use ($Order, $Finish, &$Current) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                // show processing step
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                $this->setAttribute('step', $Processing->getName());
    
    
                $Payment = $Order->getPayment();
    
                if ($Payment->getPaymentType()->isGateway() === false) {
                    $this->setAttribute('step', $Finish->getName());
                    $Current = $Finish;
    
                    try {
                        $this->send();
                    } catch (QUI\Exception $Exception) {
                        QUI\System\Log::writeException($Exception);
                    }
    
                    return false;
                }
    
    
                if (Settings::getInstance()->get('order', 'failedPaymentProcedure') === 'execute') {
                    try {
                        $this->send();
                    } catch (QUI\Exception $Exception) {
                        QUI\System\Log::writeException($Exception);
                    }
                }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                // rearrange the steps, insert the processing step
                $Steps = $this->parseSteps();
                $Steps->append($Processing);
    
                $this->sortSteps($Steps);
    
                $this->steps = $this->parseStepsToArray($Steps);
    
                $result = $this->executePayableStatus();
    
    Henning Leutz's avatar
    Henning Leutz committed
    
                if ($result === false) {
                    return false;
                }
    
                /* @var $Step AbstractOrderingStep */
                foreach ($this->getSteps() as $Step) {
                    try {
                        $Step->onExecutePayableStatus();
                    } catch (QUI\Exception $Exception) {
                        QUI\System\Log::writeDebugException($Exception);
                    }
                }
    
                return $result;
            };
    
            if (isset($_REQUEST['payableToOrder'])) {
                return $render();
            }
    
    
            // show processing step if order is not paid
    
            $paymentIsSuccessful = false;
    
            $Payment = $Order->getPayment();
    
            // @phpstan-ignore-next-line
    
            if ($Payment && $Payment->isSuccessful($Order->getUUID())) {
    
                $paymentIsSuccessful = true;
            }
    
            if ($Order instanceof Order && !$Order->isPaid() && !$paymentIsSuccessful) {
    
                // if a payment transaction exists, maybe the transaction is in pending
                // as long as, the order is "successful"
                $transactions = $Order->getTransactions();
    
                $isInPending = array_filter($transactions, function ($Transaction) {
    
                    /* @var $Transaction QUI\ERP\Accounting\Payments\Transactions\Transaction */
                    return $Transaction->isPending();
                });
    
                if (!$isInPending) {
                    return $render();
                }
    
            if (
                $Finish->getName() === $Current->getName()
                && $this->getOrder()->getDataEntry('orderedWithCosts')
            ) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                return $render();
            }
    
    
            if ($Checkout && $Checkout->getName() !== $Current->getName()) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                return false;
            }
    
            if ($this->getOrder()->getDataEntry('orderedWithCosts')) {
                return $render();
            }
    
            return false;
    
         * @return mixed
         * @throws Exception
         * @throws QUI\Exception
         * @throws QUI\ExceptionStack
         */
    
        protected function renderFinish(): mixed
    
            $Order = $this->getOrder();
    
            if ($Order instanceof Order) {
                $this->Order = null;
            }
    
    
            $Basket = $this->getBasket();
    
    
            if ($Basket instanceof Basket\Basket) {
                $Basket->clear();
            }
    
    Henning Leutz's avatar
    Henning Leutz committed
            $template = dirname(__FILE__) . '/Controls/OrderProcess.html';
    
            $Engine = QUI::getTemplateManager()->getEngine();
    
            $steps = $this->getSteps();
            $LastStep = $this->getLastStep();
            $Site = $this->getSite();
            $stepHash = $this->getStepHash();
    
            $stepControl = QUI\ControlUtils::parse($LastStep);
    
    
                'listWidth' => floor(100 / count($steps)),
                'this' => $this,
                'error' => false,
                'next' => false,
                'previous' => false,
                'payableToOrder' => false,
                'steps' => $steps,
                'CurrentStep' => $LastStep,
    
                'currentStepContent' => $stepControl,
    
                'Site' => $Site,
                'Order' => $Order,
                'hash' => $stepHash,
                'backToShopUrl' => $this->getBackToShopUrl()
    
            ]);
    
            $this->Events->fireEvent('getBody', [$this]);
            $this->Events->fireEvent('renderFinish', [$this]);
    
            return QUI\Output::getInstance()->parse($Engine->fetch($template));
        }
    
    
         * @return Processing|AbstractOrderingStep
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws Exception
    
         * @throws Exception
    
        public function getCurrentStep(): Controls\OrderProcess\Processing | AbstractOrderingStep
    
            $steps = $this->getSteps();
    
    Henning Leutz's avatar
    Henning Leutz committed
            $current = $this->getCurrentStepName();
    
            if (isset($steps[$current])) {
                return $steps[$current];
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($current === $Processing->getName()) {
                return $Processing;
            }
    
            return $this->getFirstStep();
    
         * Return the first step
    
         * @return AbstractOrderingStep
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws Exception
    
        public function getFirstStep(): AbstractOrderingStep
    
    Henning Leutz's avatar
    Henning Leutz committed
            return array_values($this->getSteps())[0];
    
         * Returns the last step of the order process
         *
    
        public function getLastStep(): mixed
    
    Henning Leutz's avatar
    Henning Leutz committed
            $steps = array_values($this->getSteps());
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $steps[count($steps) - 1];
    
         * @param AbstractOrderingStep|null $StartStep
    
         * @return FinishControl|bool|AbstractOrderingStep
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws Exception
    
        public function getNextStep(
            null | AbstractOrderingStep $StartStep = null
        ): FinishControl | bool | AbstractOrderingStep {
    
            if ($StartStep === null) {
                $step = $this->getCurrentStepName();
            } else {
                $step = $StartStep->getName();
    
            $Order = $this->getOrder();
    
            if (!$Order) {
                return false;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            // special -> processing step
            /* @var $Processing AbstractOrderingStep */
    
    Henning Leutz's avatar
    Henning Leutz committed
    
    
            if ($step === $Processing->getName() && !$Order->isSuccessful()) {
    
                $this->setAttribute('orderHash', $Order->getUUID());