Passed
Push — master ( 28073e...99ed61 )
by Christian
11:34 queued 10s
created

CheckoutController::order()   B

Complexity

Conditions 6
Paths 33

Size

Total Lines 34
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

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