Completed
Push — master ( 38e980...02483d )
by Joachim
02:23
created

PaymentController::captureAction()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 25
Code Lines 14

Duplication

Lines 25
Ratio 100 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 25
loc 25
rs 8.439
cc 5
eloc 14
nc 10
nop 2
1
<?php
2
3
namespace Loevgaard\DandomainAltapayBundle\Controller;
4
5
use Loevgaard\AltaPay;
6
use Loevgaard\Dandomain\Pay\Helper\ChecksumHelper;
7
use Loevgaard\DandomainAltapayBundle\Annotation\LogHttpTransaction;
8
use Loevgaard\DandomainAltapayBundle\Entity\Payment;
9
use Loevgaard\DandomainAltapayBundle\Event\PaymentCreated;
10
use Loevgaard\DandomainAltapayBundle\Exception\AltapayPaymentRequestException;
11
use Loevgaard\DandomainAltapayBundle\Exception\ChecksumMismatchException;
12
use Loevgaard\DandomainAltapayBundle\Exception\PaymentException;
13
use Loevgaard\DandomainAltapayBundle\Exception\TerminalNotFoundException;
14
use Loevgaard\DandomainAltapayBundle\Handler\PaymentHandler;
15
use Loevgaard\DandomainAltapayBundle\PayloadGenerator\PaymentRequestPayloadGenerator;
16
use Loevgaard\DandomainAltapayBundle\PsrHttpMessage\DiactorosTrait;
17
use Loevgaard\DandomainAltapayBundle\Translation\TranslatorTrait;
18
use Money\Currency;
19
use Money\Money;
20
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
21
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
22
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
23
use Symfony\Component\HttpFoundation\RedirectResponse;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Response;
26
27
/**
28
 * @Route("/payment")
29
 */
30
class PaymentController extends Controller
31
{
32
    use TranslatorTrait;
33
    use DiactorosTrait;
34
35
    /**
36
     * @Method("GET")
37
     * @Route("", name="loevgaard_dandomain_altapay_payment_index")
38
     *
39
     * @param Request $request
40
     *
41
     * @return Response
42
     */
43
    public function indexAction(Request $request)
44
    {
45
        $paymentRepository = $this->container->get('loevgaard_dandomain_altapay.payment_repository');
46
47
        /** @var Payment[] $payments */
48
        $payments = $paymentRepository->findAllWithPaging($request->query->getInt('page', 1), 100, [
49
            'e.id' => 'desc'
50
        ]);
51
52
        return $this->render('@LoevgaardDandomainAltapay/payment/index.html.twig', [
53
            'payments' => $payments,
54
        ]);
55
    }
56
57
    /**
58
     * @Method("GET")
59
     * @Route("/{paymentId}/show", name="loevgaard_dandomain_altapay_payment_show", requirements={"paymentId" = "\d+"})
60
     *
61
     * @param int $paymentId
62
     *
63
     * @return Response
64
     */
65
    public function showAction(int $paymentId)
66
    {
67
        $payment = $this->getPaymentFromId($paymentId);
68
        if (!$payment) {
69
            throw $this->createNotFoundException('Payment with id `'.$paymentId.'` not found');
70
        }
71
72
        return $this->render('@LoevgaardDandomainAltapay/payment/show.html.twig', [
73
            'payment' => $payment,
74
        ]);
75
    }
76
77
    /**
78
     * Payment flow
79
     * 1. The Dandomain payment API POSTs to this page with the terminal slug in the URL
80
     * 2. After validating all input, we create a payment request to the Altapay API
81
     * 3. Finally we redirect the user to the URL given by the Altapay API.
82
     *
83
     * @Method("POST")
84
     * @Route("/{terminal}", name="loevgaard_dandomain_altapay_payment_new")
85
     *
86
     * @LogHttpTransaction()
87
     *
88
     * @param string  $terminal
89
     * @param Request $request
90
     *
91
     * @return RedirectResponse
92
     *
93
     * @throws PaymentException
94
     */
95
    public function newAction(string $terminal, Request $request)
96
    {
97
        $terminalRepository = $this->container->get('loevgaard_dandomain_altapay.terminal_repository');
98
        $paymentRepository = $this->container->get('loevgaard_dandomain_altapay.payment_repository');
99
        $eventRepository = $this->container->get('loevgaard_dandomain_altapay.event_repository');
100
        $translator = $this->getTranslator($this->container);
101
102
        $psrRequest = $this->createPsrRequest($request);
103
        /** @var Payment $paymentEntity */
104
        $paymentEntity = Payment::createFromRequest($psrRequest);
105
106
        $checksumHelper = new ChecksumHelper(
107
            $paymentEntity,
108
            $this->container->getParameter('loevgaard_dandomain_altapay.shared_key_1'),
109
            $this->container->getParameter('loevgaard_dandomain_altapay.shared_key_2')
110
        );
111
112
        $paymentRepository->save($paymentEntity);
113
114
        $event = $eventRepository->createFromDomainEvent(new PaymentCreated($paymentEntity));
115
        $eventRepository->save($event);
116
117
        $terminalEntity = $terminalRepository->findTerminalBySlug($terminal, true);
118
        if (!$terminalEntity) {
119
            throw TerminalNotFoundException::create($translator->trans('payment.exception.terminal_not_found', ['%terminal%' => $terminal], 'LoevgaardDandomainAltapayBundle'), $request, $paymentEntity);
120
        }
121
122
        if (!$checksumHelper->checksumMatches()) {
123
            throw ChecksumMismatchException::create($translator->trans('payment.exception.checksum_mismatch', [], 'LoevgaardDandomainAltapayBundle'), $request, $paymentEntity);
124
        }
125
126
        $paymentRequestPayloadGenerator = new PaymentRequestPayloadGenerator($this->container->get('router'), $paymentEntity, $terminalEntity, $paymentEntity, $checksumHelper, $this->container->getParameter('loevgaard_dandomain_altapay.cookie_payment_id'), $this->container->getParameter('loevgaard_dandomain_altapay.cookie_checksum_complete'));
127
        $paymentRequestPayload = $paymentRequestPayloadGenerator->generate();
128
129
        $altapay = $this->container->get('loevgaard_dandomain_altapay.altapay_client');
130
        $response = $altapay->createPaymentRequest($paymentRequestPayload);
131
132
        if (!$response->isSuccessful()) {
133
            throw AltapayPaymentRequestException::create($translator->trans('payment.exception.altapay_payment_request', ['%gateway_message%' => $response->getErrorMessage()], 'LoevgaardDandomainAltapayBundle'), $request, $paymentEntity);
134
        }
135
136
        return $this->redirect($response->getUrl());
137
    }
138
139
    /**
140
     * @Method("POST")
141
     * @Route("/bulk/capture", name="loevgaard_dandomain_altapay_payment_bulk")
142
     *
143
     * @param Request $request
144
     *
145
     * @return RedirectResponse
146
     */
147
    public function bulkPaymentAction(Request $request)
148
    {
149
        $op = $request->request->getAlpha('bulkOperation');
150
        $paymentRepository = $this->container->get('loevgaard_dandomain_altapay.payment_repository');
151
        $payments = $paymentRepository->findByIds($request->request->get('payments', []));
152
153
        if($op === 'capture') {
154
            $paymentHandler = $this->getPaymentHandler();
155
            $paymentHandler->bulkCapture($payments);
156
157
            $this->addFlash('success', 'All payments were captured'); // @todo fix translation
158
        }
159
160
        return $this->redirectToRoute('loevgaard_dandomain_altapay_payment_index');
161
    }
162
163
    /**
164
     * @Method("GET")
165
     * @Route("/{paymentId}/capture", name="loevgaard_dandomain_altapay_payment_capture", requirements={"paymentId" = "\d+"})
166
     *
167
     * @param int     $paymentId
168
     * @param Request $request
169
     *
170
     * @return RedirectResponse
171
     */
172 View Code Duplication
    public function captureAction(int $paymentId, Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
    {
174
        $payment = $this->getPaymentFromId($paymentId);
175
176
        if ($payment) {
177
            $paymentHandler = $this->getPaymentHandler();
178
179
            $amount = $request->query->get('amount');
180
            if($amount) {
181
                $amount = AltaPay\createMoneyFromFloat($payment->getCurrencySymbol(), $amount);
182
            }
183
184
            $res = $paymentHandler->capture($payment, $amount);
185
186
            if ($res->isSuccessful()) {
187
                $this->addFlash('success', 'The payment for order '.$payment->getOrderId().' was captured.'); // @todo fix translation
188
            } else {
189
                $this->addFlash('danger', 'An error occurred during capture of the payment: '.$res->getErrorMessage()); // @todo fix translation
190
            }
191
        }
192
193
        $redirect = $request->headers->get('referer') ? $request->headers->get('referer') : $this->generateUrl('loevgaard_dandomain_altapay_payment_index');
194
195
        return $this->redirect($redirect);
0 ignored issues
show
Bug introduced by
It seems like $redirect defined by $request->headers->get('...altapay_payment_index') on line 193 can also be of type array; however, Symfony\Bundle\Framework...rollerTrait::redirect() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
196
    }
197
198
    /**
199
     * @Method({"POST", "GET"})
200
     * @Route("/{paymentId}/refund", name="loevgaard_dandomain_altapay_payment_refund", requirements={"paymentId" = "\d+"})
201
     *
202
     * @param int     $paymentId
203
     * @param Request $request
204
     *
205
     * @return RedirectResponse
206
     */
207 View Code Duplication
    public function refundAction(int $paymentId, Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
    {
209
        $payment = $this->getPaymentFromId($paymentId);
210
211
        if ($payment) {
212
            $paymentHandler = $this->getPaymentHandler();
213
214
            $amount = $request->query->get('amount');
215
            if ($amount) {
216
                $amount = AltaPay\createMoneyFromFloat($payment->getCurrencySymbol(), $amount);
217
            }
218
219
            $res = $paymentHandler->refund($payment, $amount);
220
221
            if ($res->isSuccessful()) {
222
                $this->addFlash('success', 'The payment for order '.$payment->getOrderId().' was refunded.'); // @todo fix translation
223
            } else {
224
                $this->addFlash('danger', 'An error occurred during refund of the payment: '.$res->getErrorMessage()); // @todo fix translation
225
            }
226
        }
227
228
        $redirect = $request->headers->get('referer') ?: $this->generateUrl('loevgaard_dandomain_altapay_payment_index');
229
230
        return $this->redirect($redirect);
0 ignored issues
show
Bug introduced by
It seems like $redirect defined by $request->headers->get('...altapay_payment_index') on line 228 can also be of type array; however, Symfony\Bundle\Framework...rollerTrait::redirect() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
231
    }
232
233
    /**
234
     * @Method("GET")
235
     * @Route("/{paymentId}/redirectToAltapay", name="loevgaard_dandomain_altapay_redirect_to_altapay_payment", requirements={"paymentId" = "\d+"})
236
     *
237
     * @param int $paymentId
238
     *
239
     * @return RedirectResponse
240
     */
241
    public function redirectToAltapayPaymentAction(int $paymentId)
242
    {
243
        $payment = $this->getPaymentFromId($paymentId);
244
245
        $url = $this->getParameter('loevgaard_dandomain_altapay.altapay_url').'/merchant/transactions/paymentDetails/'.$payment->getAltapayId();
246
247
        return $this->redirect($url);
248
    }
249
250
    /**
251
     * @param int $paymentId
252
     *
253
     * @return Payment
254
     */
255 View Code Duplication
    private function getPaymentFromId(int $paymentId): Payment
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
256
    {
257
        $paymentRepository = $this->get('loevgaard_dandomain_altapay.payment_repository');
258
259
        /** @var Payment $payment */
260
        $payment = $paymentRepository->find($paymentId);
261
262
        if (!$payment) {
263
            throw $this->createNotFoundException('Payment with id `'.$paymentId.'` not found');
264
        }
265
266
        return $payment;
267
    }
268
269
    /**
270
     * @return PaymentHandler
271
     */
272
    private function getPaymentHandler(): PaymentHandler
273
    {
274
        return $this->get('loevgaard_dandomain_altapay.payment_handler');
275
    }
276
}
277