Passed
Push — master ( 97d661...e1fe1a )
by Christian
18:59 queued 08:35
created

SetPaymentOrderRoute   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 56
dl 0
loc 146
rs 10
c 0
b 0
f 0
wmc 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A getDecorated() 0 3 1
A validateRequest() 0 9 2
A setPayment() 0 9 1
A setPaymentMethod() 0 60 5
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\Checkout\Order\SalesChannel;
4
5
use OpenApi\Annotations as OA;
6
use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
7
use Shopware\Core\Checkout\Customer\CustomerEntity;
8
use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStates;
9
use Shopware\Core\Checkout\Order\OrderEntity;
10
use Shopware\Core\Checkout\Payment\Exception\UnknownPaymentMethodException;
11
use Shopware\Core\Checkout\Payment\SalesChannel\PaymentMethodRoute;
12
use Shopware\Core\Framework\Context;
13
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
14
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
15
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
16
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
17
use Shopware\Core\Framework\Routing\Annotation\LoginRequired;
18
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
19
use Shopware\Core\Framework\Routing\Annotation\Since;
20
use Shopware\Core\Framework\Uuid\Uuid;
21
use Shopware\Core\System\SalesChannel\SalesChannelContext;
22
use Shopware\Core\System\StateMachine\StateMachineRegistry;
23
use Symfony\Component\HttpFoundation\ParameterBag;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\Routing\Annotation\Route;
26
27
/**
28
 * @RouteScope(scopes={"store-api"})
29
 */
30
class SetPaymentOrderRoute extends AbstractSetPaymentOrderRoute
31
{
32
    /**
33
     * @var EntityRepositoryInterface
34
     */
35
    private $orderRepository;
36
37
    /**
38
     * @var PaymentMethodRoute
39
     */
40
    private $paymentRoute;
41
42
    /**
43
     * @var StateMachineRegistry
44
     */
45
    private $stateMachineRegistry;
46
47
    /**
48
     * @var OrderService
49
     */
50
    private $orderService;
51
52
    public function __construct(
53
        OrderService $orderService,
54
        EntityRepositoryInterface $orderRepository,
55
        PaymentMethodRoute $paymentRoute,
56
        StateMachineRegistry $stateMachineRegistry
57
    ) {
58
        $this->orderService = $orderService;
59
        $this->orderRepository = $orderRepository;
60
        $this->paymentRoute = $paymentRoute;
61
        $this->stateMachineRegistry = $stateMachineRegistry;
62
    }
63
64
    public function getDecorated(): AbstractSetPaymentOrderRoute
65
    {
66
        throw new DecorationPatternException(self::class);
67
    }
68
69
    /**
70
     * @Since("6.2.0.0")
71
     * @OA\Post(
72
     *      path="/order/payment",
73
     *      summary="set payment for an order",
74
     *      operationId="orderSetPayment",
75
     *      tags={"Store API", "Account"},
76
     *      @OA\RequestBody(
77
     *          required=true,
78
     *          @OA\JsonContent(
79
     *              @OA\Property(property="paymentMethodId", description="The id of the paymentMethod to be set", type="string"),
80
     *              @OA\Property(property="orderId", description="The id of the order", type="string")
81
     *          )
82
     *      ),
83
     *      @OA\Response(
84
     *          response="200",
85
     *          description="Successfully set a payment",
86
     *          @OA\JsonContent(ref="#/components/schemas/SuccessResponse")
87
     *     )
88
     * )
89
     * @LoginRequired()
90
     * @Route(path="/store-api/v{version}/order/payment", name="store-api.order.set-payment", methods={"POST"})
91
     */
92
    public function setPayment(Request $request, SalesChannelContext $context): SetPaymentOrderRouteResponse
93
    {
94
        $paymentMethodId = $request->get('paymentMethodId');
95
96
        $this->validateRequest($context, $paymentMethodId);
0 ignored issues
show
Bug introduced by
It seems like $paymentMethodId can also be of type null; however, parameter $paymentMethodId of Shopware\Core\Checkout\O...oute::validateRequest() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

96
        $this->validateRequest($context, /** @scrutinizer ignore-type */ $paymentMethodId);
Loading history...
97
98
        $this->setPaymentMethod($paymentMethodId, $request->get('orderId'), $context);
0 ignored issues
show
Bug introduced by
It seems like $request->get('orderId') can also be of type null; however, parameter $orderId of Shopware\Core\Checkout\O...ute::setPaymentMethod() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

98
        $this->setPaymentMethod($paymentMethodId, /** @scrutinizer ignore-type */ $request->get('orderId'), $context);
Loading history...
99
100
        return new SetPaymentOrderRouteResponse();
101
    }
102
103
    private function setPaymentMethod(string $paymentMethodId, string $orderId, SalesChannelContext $salesChannelContext): void
104
    {
105
        $context = $salesChannelContext->getContext();
106
        $initialState = $this->stateMachineRegistry->getInitialState(
107
            OrderTransactionStates::STATE_MACHINE,
108
            $context
109
        );
110
111
        $criteria = new Criteria([$orderId]);
112
        $criteria->addAssociation('transactions');
113
114
        /** @var CustomerEntity $customer */
115
        $customer = $salesChannelContext->getCustomer();
116
117
        $criteria->addFilter(
118
            new EqualsFilter(
119
                'order.orderCustomer.customerId',
120
                $customer->getId()
121
            )
122
        );
123
124
        /** @var OrderEntity $order */
125
        $order = $this->orderRepository->search($criteria, $context)->first();
126
127
        $context->scope(
128
            Context::SYSTEM_SCOPE,
129
            function () use ($order, $initialState, $orderId, $paymentMethodId, $context): void {
130
                if ($order->getTransactions() !== null && $order->getTransactions()->count() >= 1) {
131
                    foreach ($order->getTransactions() as $transaction) {
132
                        if ($transaction->getStateMachineState()->getTechnicalName() !== OrderTransactionStates::STATE_CANCELLED) {
133
                            $this->orderService->orderTransactionStateTransition(
134
                                $transaction->getId(),
135
                                'cancel',
136
                                new ParameterBag(),
137
                                $context
138
                            );
139
                        }
140
                    }
141
                }
142
                $transactionId = Uuid::randomHex();
143
                $transactionAmount = new CalculatedPrice(
144
                    $order->getPrice()->getTotalPrice(),
145
                    $order->getPrice()->getTotalPrice(),
146
                    $order->getPrice()->getCalculatedTaxes(),
147
                    $order->getPrice()->getTaxRules()
148
                );
149
150
                $this->orderRepository->update([
151
                    [
152
                        'id' => $orderId,
153
                        'transactions' => [
154
                            [
155
                                'id' => $transactionId,
156
                                'paymentMethodId' => $paymentMethodId,
157
                                'stateId' => $initialState->getId(),
158
                                'amount' => $transactionAmount,
159
                            ],
160
                        ],
161
                    ],
162
                ], $context);
163
            }
164
        );
165
    }
166
167
    private function validateRequest(SalesChannelContext $salesChannelContext, string $paymentMethodId): void
168
    {
169
        $paymentRequest = new Request();
170
        $paymentRequest->query->set('onlyAvailable', 1);
171
172
        $availablePayments = $this->paymentRoute->load($paymentRequest, $salesChannelContext);
173
174
        if ($availablePayments->getPaymentMethods()->get($paymentMethodId) === null) {
175
            throw new UnknownPaymentMethodException($paymentMethodId);
176
        }
177
    }
178
}
179