Refund::applyStateMachineTransition()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file has been created by developers from BitBag.
5
 * Feel free to contact us once you face any issues or want to start
6
 * You can find more information about us on https://bitbag.io and write us
7
 * an email on [email protected].
8
 */
9
10
declare(strict_types=1);
11
12
namespace BitBag\SyliusMolliePlugin\Controller\Action\Admin;
13
14
use BitBag\SyliusMolliePlugin\Factory\MollieGatewayFactory;
15
use BitBag\SyliusMolliePlugin\Logger\MollieLoggerActionInterface;
16
use BitBag\SyliusMolliePlugin\Request\Api\RefundOrder;
17
use Doctrine\ORM\EntityManagerInterface;
18
use Payum\Core\Model\GatewayConfigInterface;
19
use Payum\Core\Payum;
20
use Payum\Core\Request\Refund as RefundAction;
21
use Payum\Core\Security\TokenInterface;
22
use SM\Factory\FactoryInterface;
23
use Sylius\Component\Core\Model\PaymentInterface;
24
use Sylius\Component\Core\Model\PaymentMethodInterface;
25
use Sylius\Component\Core\Repository\PaymentRepositoryInterface;
26
use Sylius\Component\Payment\PaymentTransitions;
27
use Sylius\Component\Resource\Exception\UpdateHandlingException;
28
use Symfony\Component\HttpFoundation\RedirectResponse;
29
use Symfony\Component\HttpFoundation\Request;
30
use Symfony\Component\HttpFoundation\Response;
31
use Symfony\Component\HttpFoundation\Session\Session;
32
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
33
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
34
35
final class Refund
36
{
37
    /** @var PaymentRepositoryInterface */
38
    private $paymentRepository;
39
40
    /** @var Payum */
41
    private $payum;
42
43
    /** @var Session */
44
    private $session;
45
46
    /** @var FactoryInterface */
47
    private $stateMachineFactory;
48
49
    /** @var EntityManagerInterface */
50
    private $paymentEntityManager;
51
52
    /** @var MollieLoggerActionInterface */
53
    private $loggerAction;
54
55
    public function __construct(
56
        PaymentRepositoryInterface $paymentRepository,
57
        Payum $payum,
58
        Session $session,
59
        FactoryInterface $stateMachineFactory,
60
        EntityManagerInterface $paymentEntityManager,
61
        MollieLoggerActionInterface $loggerAction
62
    ) {
63
        $this->paymentRepository = $paymentRepository;
64
        $this->payum = $payum;
65
        $this->session = $session;
66
        $this->stateMachineFactory = $stateMachineFactory;
67
        $this->paymentEntityManager = $paymentEntityManager;
68
        $this->loggerAction = $loggerAction;
69
    }
70
71
    public function __invoke(Request $request): Response
72
    {
73
        /** @var PaymentInterface|null $payment */
74
        $payment = $this->paymentRepository->find($request->get('id'));
75
76
        if (null === $payment) {
77
            $this->loggerAction->addNegativeLog(sprintf('Not fount payment in refund'));
78
79
            throw new NotFoundHttpException();
80
        }
81
82
        /** @var PaymentMethodInterface $paymentMethod */
83
        $paymentMethod = $payment->getMethod();
84
85
        /** @var GatewayConfigInterface $gatewayConfig */
86
        $gatewayConfig = $paymentMethod->getGatewayConfig();
87
        $factoryName = $gatewayConfig->getFactoryName() ?? null;
0 ignored issues
show
Deprecated Code introduced by
The function Payum\Core\Model\Gateway...rface::getFactoryName() has been deprecated: since 1.3.3 will be removed in 2.0. set factory option inside the config ( Ignorable by Annotation )

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

87
        $factoryName = /** @scrutinizer ignore-deprecated */ $gatewayConfig->getFactoryName() ?? null;

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
88
89
        if (MollieGatewayFactory::FACTORY_NAME !== $factoryName) {
90
            $this->applyStateMachineTransition($payment);
91
92
            $this->session->getFlashBag()->add('success', 'sylius.payment.refunded');
93
            $this->loggerAction->addLog(sprintf('Refunded successfully'));
94
95
            return $this->redirectToReferer($request);
96
        }
97
        if (
98
            (!isset($payment->getDetails()['payment_mollie_id']) || !isset($payment->getDetails()['metadata']['refund_token'])) &&
99
            !isset($payment->getDetails()['order_mollie_id'])
100
        ) {
101
            $this->applyStateMachineTransition($payment);
102
103
            $this->session->getFlashBag()->add('info', 'bitbag_sylius_mollie_plugin.ui.refunded_only_locally');
104
            $this->loggerAction->addLog(sprintf('Refunded only locally'));
105
106
            return $this->redirectToReferer($request);
107
        }
108
109
        $hash = $payment->getDetails()['metadata']['refund_token'];
110
111
        /** @var TokenInterface|null $token */
112
        $token = $this->payum->getTokenStorage()->find($hash);
113
114
        if (null === $token || !$token instanceof TokenInterface) {
115
            $this->loggerAction->addNegativeLog(sprintf('A token with hash `%s` could not be found.', $hash));
116
117
            throw new BadRequestHttpException(sprintf('A token with hash `%s` could not be found.', $hash));
118
        }
119
120
        $gateway = $this->payum->getGateway($token->getGatewayName());
121
122
        try {
123
            if (isset($payment->getDetails()['order_mollie_id'])) {
124
                $gateway->execute(new RefundOrder($token));
125
            } else {
126
                $gateway->execute(new RefundAction($token));
127
            }
128
129
            $this->applyStateMachineTransition($payment);
130
131
            $this->session->getFlashBag()->add('success', 'sylius.payment.refunded');
132
        } catch (UpdateHandlingException $e) {
133
            $this->loggerAction->addNegativeLog(sprintf('Error with refund: %s', $e->getMessage()));
134
            $this->session->getFlashBag()->add('error', $e->getMessage());
135
        }
136
137
        return $this->redirectToReferer($request);
138
    }
139
140
    private function applyStateMachineTransition(PaymentInterface $payment): void
141
    {
142
        $stateMachine = $this->stateMachineFactory->get($payment, PaymentTransitions::GRAPH);
143
144
        if (!$stateMachine->can(PaymentTransitions::TRANSITION_REFUND)) {
145
            throw new BadRequestHttpException();
146
        }
147
148
        $stateMachine->apply(PaymentTransitions::TRANSITION_REFUND);
149
150
        $this->paymentEntityManager->flush();
151
    }
152
153
    private function redirectToReferer(Request $request): Response
154
    {
155
        /** @var string $url */
156
        $url = $request->headers->get('referer', null, true);
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Component\HttpFoundation\HeaderBag::get() has too many arguments starting with true. ( Ignorable by Annotation )

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

156
        /** @scrutinizer ignore-call */ 
157
        $url = $request->headers->get('referer', null, true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
157
158
        return new RedirectResponse($url);
159
    }
160
}
161