Passed
Push — master ( b21036...8d84d5 )
by Christian
11:52 queued 12s
created

CheckoutController::order()   A

Complexity

Conditions 6
Paths 26

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 17
nc 26
nop 3
dl 0
loc 27
rs 9.0777
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Storefront\Controller;
4
5
use Shopware\Core\Checkout\Cart\Error\Error;
6
use Shopware\Core\Checkout\Cart\Exception\CartTokenNotFoundException;
7
use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;
8
use Shopware\Core\Checkout\Cart\Exception\OrderNotFoundException;
9
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
10
use Shopware\Core\Checkout\Order\Exception\EmptyCartException;
11
use Shopware\Core\Checkout\Order\SalesChannel\OrderService;
12
use Shopware\Core\Checkout\Payment\Exception\InvalidOrderException;
13
use Shopware\Core\Checkout\Payment\Exception\PaymentProcessException;
14
use Shopware\Core\Checkout\Payment\Exception\UnknownPaymentMethodException;
15
use Shopware\Core\Checkout\Payment\PaymentService;
16
use Shopware\Core\Framework\Feature;
17
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
18
use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
19
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
20
use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
21
use Shopware\Core\System\SalesChannel\SalesChannelContext;
22
use Shopware\Storefront\Framework\AffiliateTracking\AffiliateTrackingListener;
23
use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoader;
24
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoader;
25
use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoader;
26
use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoader;
27
use Symfony\Component\HttpFoundation\RedirectResponse;
28
use Symfony\Component\HttpFoundation\Request;
29
use Symfony\Component\HttpFoundation\Response;
30
use Symfony\Component\HttpFoundation\Session\SessionInterface;
31
use Symfony\Component\Routing\Annotation\Route;
32
33
/**
34
 * @RouteScope(scopes={"storefront"})
35
 */
36
class CheckoutController extends StorefrontController
37
{
38
    /**
39
     * @var CartService
40
     */
41
    private $cartService;
42
43
    /**
44
     * @var CheckoutCartPageLoader
45
     */
46
    private $cartPageLoader;
47
48
    /**
49
     * @var CheckoutConfirmPageLoader
50
     */
51
    private $confirmPageLoader;
52
53
    /**
54
     * @var CheckoutFinishPageLoader
55
     */
56
    private $finishPageLoader;
57
58
    /**
59
     * @var OrderService
60
     */
61
    private $orderService;
62
63
    /**
64
     * @var PaymentService
65
     */
66
    private $paymentService;
67
68
    /**
69
     * @var OffcanvasCartPageLoader
70
     */
71
    private $offcanvasCartPageLoader;
72
73
    public function __construct(
74
        CartService $cartService,
75
        CheckoutCartPageLoader $cartPageLoader,
76
        CheckoutConfirmPageLoader $confirmPageLoader,
77
        CheckoutFinishPageLoader $finishPageLoader,
78
        OrderService $orderService,
79
        PaymentService $paymentService,
80
        OffcanvasCartPageLoader $offcanvasCartPageLoader
81
    ) {
82
        $this->cartService = $cartService;
83
        $this->cartPageLoader = $cartPageLoader;
84
        $this->confirmPageLoader = $confirmPageLoader;
85
        $this->finishPageLoader = $finishPageLoader;
86
        $this->orderService = $orderService;
87
        $this->paymentService = $paymentService;
88
        $this->offcanvasCartPageLoader = $offcanvasCartPageLoader;
89
    }
90
91
    /**
92
     * @Route("/checkout/cart", name="frontend.checkout.cart.page", options={"seo"="false"}, methods={"GET"})
93
     */
94
    public function cartPage(Request $request, SalesChannelContext $context): Response
95
    {
96
        $page = $this->cartPageLoader->load($request, $context);
97
98
        return $this->renderStorefront('@Storefront/storefront/page/checkout/cart/index.html.twig', ['page' => $page]);
99
    }
100
101
    /**
102
     * @Route("/checkout/confirm", name="frontend.checkout.confirm.page", options={"seo"="false"}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
103
     */
104
    public function confirmPage(Request $request, SalesChannelContext $context): Response
105
    {
106
        if (!$context->getCustomer()) {
107
            return $this->redirectToRoute('frontend.checkout.register.page');
108
        }
109
110
        if ($this->cartService->getCart($context->getToken(), $context)->getLineItems()->count() === 0) {
111
            return $this->redirectToRoute('frontend.checkout.cart.page');
112
        }
113
114
        $page = $this->confirmPageLoader->load($request, $context);
115
116
        return $this->renderStorefront('@Storefront/storefront/page/checkout/confirm/index.html.twig', ['page' => $page]);
117
    }
118
119
    /**
120
     * @Route("/checkout/finish", name="frontend.checkout.finish.page", options={"seo"="false"}, methods={"GET"})
121
     *
122
     * @throws CustomerNotLoggedInException
123
     * @throws MissingRequestParameterException
124
     * @throws OrderNotFoundException
125
     */
126
    public function finishPage(Request $request, SalesChannelContext $context): Response
127
    {
128
        if (!$context->getCustomer()) {
129
            return $this->redirectToRoute('frontend.checkout.register.page');
130
        }
131
132
        $page = $this->finishPageLoader->load($request, $context);
133
134
        if ($page->isPaymentFailed() === true) {
135
            // @deprecated tag:v6.4.0 - errors will be redirected immediately to the edit order page
136
            $this->addFlash(
137
                'danger',
138
                $this->trans(
139
                    'checkout.finishPaymentFailed',
140
                    [
141
                        '%editOrderUrl%' => $this->generateUrl('frontend.account.edit-order.page', ['orderId' => $request->get('orderId')]),
142
                    ]
143
                )
144
            );
145
        }
146
147
        return $this->renderStorefront('@Storefront/storefront/page/checkout/finish/index.html.twig', ['page' => $page]);
148
    }
149
150
    /**
151
     * @Route("/checkout/order", name="frontend.checkout.finish.order", options={"seo"="false"}, methods={"POST"})
152
     */
153
    public function order(RequestDataBag $data, SalesChannelContext $context, Request $request): Response
154
    {
155
        if (!$context->getCustomer()) {
156
            return $this->redirectToRoute('frontend.checkout.register.page');
157
        }
158
159
        $formViolations = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $formViolations is dead and can be removed.
Loading history...
160
161
        $orderId = null;
162
163
        try {
164
            $this->addAffiliateTracking($data, $request->getSession());
165
            $orderId = $this->orderService->createOrder($data, $context);
166
            $finishUrl = $this->generateUrl('frontend.checkout.finish.page', ['orderId' => $orderId]);
167
            $errorUrl = $this->generateUrl('frontend.account.edit-order.page', ['orderId' => $orderId]);
168
169
            $response = $this->paymentService->handlePaymentByOrder($orderId, $data, $context, $finishUrl, $errorUrl);
170
171
            return $response ?? new RedirectResponse($finishUrl);
172
        } catch (ConstraintViolationException $formViolations) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
173
        } catch (Error $blockedError) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
174
        } catch (EmptyCartException $blockedError) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
175
        } catch (PaymentProcessException | InvalidOrderException | UnknownPaymentMethodException $e) {
176
            return $this->forwardToRoute('frontend.checkout.finish.page', ['orderId' => $orderId, 'changedPayment' => false, 'paymentFailed' => true]);
177
        }
178
179
        return $this->forwardToRoute('frontend.checkout.confirm.page', ['formViolations' => $formViolations]);
180
    }
181
182
    /**
183
     * @Route("/widgets/checkout/info", name="frontend.checkout.info", methods={"GET"}, defaults={"XmlHttpRequest"=true})
184
     *
185
     * @throws CartTokenNotFoundException
186
     */
187
    public function info(Request $request, SalesChannelContext $context): Response
188
    {
189
        $page = $this->offcanvasCartPageLoader->load($request, $context);
190
191
        return $this->renderStorefront('@Storefront/storefront/layout/header/actions/cart-widget.html.twig', ['page' => $page]);
192
    }
193
194
    /**
195
     * @Route("/checkout/offcanvas", name="frontend.cart.offcanvas", options={"seo"="false"}, methods={"GET"}, defaults={"XmlHttpRequest"=true})
196
     *
197
     * @throws CartTokenNotFoundException
198
     */
199
    public function offcanvas(Request $request, SalesChannelContext $context): Response
200
    {
201
        $page = $this->offcanvasCartPageLoader->load($request, $context);
202
        if (Feature::isActive('FEATURE_NEXT_10058')) {
203
            if ($request->cookies->get('sf_redirect') === null) {
204
                $cart = $page->getCart();
205
                $this->addCartErrors($cart);
206
                $cart->getErrors()->clear();
207
            }
208
        }
209
210
        return $this->renderStorefront('@Storefront/storefront/component/checkout/offcanvas-cart.html.twig', ['page' => $page]);
211
    }
212
213
    private function addAffiliateTracking(RequestDataBag $dataBag, SessionInterface $session): void
214
    {
215
        $affiliateCode = $session->get(AffiliateTrackingListener::AFFILIATE_CODE_KEY);
216
        $campaignCode = $session->get(AffiliateTrackingListener::CAMPAIGN_CODE_KEY);
217
        if ($affiliateCode !== null && $campaignCode !== null) {
218
            $dataBag->set(AffiliateTrackingListener::AFFILIATE_CODE_KEY, $affiliateCode);
219
            $dataBag->set(AffiliateTrackingListener::CAMPAIGN_CODE_KEY, $campaignCode);
220
        }
221
    }
222
}
223