getPaymentMethodTransferFromRequestTransfer()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 11
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 18
rs 9.9
1
<?php
2
3
/**
4
 * Copyright © 2016-present Spryker Systems GmbH. All rights reserved.
5
 * Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file.
6
 */
7
8
namespace Spryker\Zed\Payment\Business\ForeignPayment;
9
10
use Generated\Shared\Transfer\AcpHttpRequestTransfer;
11
use Generated\Shared\Transfer\AcpHttpResponseTransfer;
12
use Generated\Shared\Transfer\CheckoutErrorTransfer;
13
use Generated\Shared\Transfer\CheckoutResponseTransfer;
14
use Generated\Shared\Transfer\LocaleTransfer;
15
use Generated\Shared\Transfer\PaymentAuthorizeResponseTransfer;
16
use Generated\Shared\Transfer\PaymentMethodTransfer;
17
use Generated\Shared\Transfer\PaymentProviderTransfer;
18
use Generated\Shared\Transfer\PaymentTransfer;
19
use Generated\Shared\Transfer\PreOrderPaymentRequestTransfer;
20
use Generated\Shared\Transfer\PreOrderPaymentResponseTransfer;
21
use Generated\Shared\Transfer\QuoteTransfer;
22
use Spryker\Service\Payment\PaymentServiceInterface;
23
use Spryker\Service\UtilText\Model\Url\Url;
24
use Spryker\Shared\Log\LoggerTrait;
25
use Spryker\Zed\Payment\Business\Exception\PreOrderPaymentException;
26
use Spryker\Zed\Payment\Business\Mapper\QuoteDataMapperInterface;
27
use Spryker\Zed\Payment\Dependency\Facade\PaymentToKernelAppFacadeInterface;
28
use Spryker\Zed\Payment\Dependency\Facade\PaymentToLocaleFacadeInterface;
29
use Spryker\Zed\Payment\Dependency\Service\PaymentToUtilEncodingServiceInterface;
30
use Spryker\Zed\Payment\PaymentConfig;
31
use Spryker\Zed\Payment\Persistence\PaymentRepositoryInterface;
32
use Symfony\Component\HttpFoundation\Request;
33
use Symfony\Component\HttpFoundation\Response;
34
35
class ForeignPayment implements ForeignPaymentInterface
36
{
37
    use LoggerTrait;
38
39
    /**
40
     * @var string
41
     */
42
    protected const ERROR_MESSAGE_PAYMENT_AUTHORIZATION = 'Payment provider is currently unavailable, please try again later.';
43
44
    /**
45
     * @var string
46
     */
47
    protected const ERROR_MESSAGE_PAYMENT_FAILED = 'payment failed';
48
49
    /**
50
     * @var \Spryker\Zed\Payment\Business\Mapper\QuoteDataMapperInterface
51
     */
52
    protected QuoteDataMapperInterface $quoteDataMapper;
53
54
    /**
55
     * @var \Spryker\Zed\Payment\Dependency\Facade\PaymentToLocaleFacadeInterface
56
     */
57
    protected PaymentToLocaleFacadeInterface $localeFacade;
58
59
    /**
60
     * @var \Spryker\Zed\Payment\Dependency\Facade\PaymentToKernelAppFacadeInterface
61
     */
62
    protected PaymentToKernelAppFacadeInterface $kernelAppFacade;
63
64
    /**
65
     * @var \Spryker\Zed\Payment\Persistence\PaymentRepositoryInterface
66
     */
67
    protected PaymentRepositoryInterface $paymentRepository;
68
69
    /**
70
     * @var \Spryker\Zed\Payment\PaymentConfig
71
     */
72
    protected PaymentConfig $paymentConfig;
73
74
    /**
75
     * @var \Spryker\Service\Payment\PaymentServiceInterface
76
     */
77
    protected PaymentServiceInterface $paymentService;
78
79
    /**
80
     * @var \Spryker\Zed\Payment\Dependency\Service\PaymentToUtilEncodingServiceInterface
81
     */
82
    protected PaymentToUtilEncodingServiceInterface $utilEncodingService;
83
84
    /**
85
     * @param \Spryker\Zed\Payment\Business\Mapper\QuoteDataMapperInterface $quoteDataMapper
86
     * @param \Spryker\Zed\Payment\Dependency\Facade\PaymentToLocaleFacadeInterface $localeFacade
87
     * @param \Spryker\Zed\Payment\Dependency\Facade\PaymentToKernelAppFacadeInterface $kernelAppFacade
88
     * @param \Spryker\Zed\Payment\Persistence\PaymentRepositoryInterface $paymentRepository
89
     * @param \Spryker\Zed\Payment\PaymentConfig $paymentConfig
90
     * @param \Spryker\Service\Payment\PaymentServiceInterface $paymentService
91
     * @param \Spryker\Zed\Payment\Dependency\Service\PaymentToUtilEncodingServiceInterface $utilEncodingService
92
     */
93
    public function __construct(
94
        QuoteDataMapperInterface $quoteDataMapper,
95
        PaymentToLocaleFacadeInterface $localeFacade,
96
        PaymentToKernelAppFacadeInterface $kernelAppFacade,
97
        PaymentRepositoryInterface $paymentRepository,
98
        PaymentConfig $paymentConfig,
99
        PaymentServiceInterface $paymentService,
100
        PaymentToUtilEncodingServiceInterface $utilEncodingService
101
    ) {
102
        $this->quoteDataMapper = $quoteDataMapper;
103
        $this->localeFacade = $localeFacade;
104
        $this->kernelAppFacade = $kernelAppFacade;
105
        $this->paymentRepository = $paymentRepository;
106
        $this->paymentConfig = $paymentConfig;
107
        $this->paymentService = $paymentService;
108
        $this->utilEncodingService = $utilEncodingService;
109
    }
110
111
    /**
112
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
113
     * @param \Generated\Shared\Transfer\CheckoutResponseTransfer $checkoutResponseTransfer
114
     *
115
     * @return void
116
     */
117
    public function initializePayment(
118
        QuoteTransfer $quoteTransfer,
119
        CheckoutResponseTransfer $checkoutResponseTransfer
120
    ): void {
121
        $paymentSelectionKey = $this->paymentService->getPaymentSelectionKey($quoteTransfer->getPaymentOrFail());
122
123
        if ($paymentSelectionKey !== PaymentTransfer::FOREIGN_PAYMENTS || $this->hasQuotePreOrderPaymentData($quoteTransfer)) {
124
            return;
125
        }
126
127
        $paymentMethodKey = $this->paymentService->getPaymentMethodKey($quoteTransfer->getPaymentOrFail());
128
129
        $paymentMethodTransfer = $this->paymentRepository->findPaymentMethod(
130
            (new PaymentMethodTransfer())->setPaymentMethodKey($paymentMethodKey),
131
        );
132
133
        if (!$paymentMethodTransfer || (!$paymentMethodTransfer->getPaymentAuthorizationEndpoint() && !$paymentMethodTransfer->getPaymentMethodAppConfiguration())) {
134
            return;
135
        }
136
137
        if ($paymentMethodTransfer->getPaymentMethodAppConfiguration()) {
138
            $checkoutConfigurationTransfer = $paymentMethodTransfer->getPaymentMethodAppConfiguration()->getCheckoutConfiguration();
139
140
            if ($checkoutConfigurationTransfer && $checkoutConfigurationTransfer->getStrategy() === PaymentConfig::CHECKOUT_STRATEGY_EXPRESS_CHECKOUT) {
141
                return;
142
            }
143
        }
144
145
        $saveOrderTransfer = $checkoutResponseTransfer->getSaveOrderOrFail();
146
147
        $localeTransfer = $this->localeFacade->getCurrentLocale();
148
149
        $quoteTransfer->setOrderReference($saveOrderTransfer->getOrderReference());
150
        $quoteTransfer->getCustomerOrFail()->setLocale($localeTransfer);
151
152
        $language = $this->getCurrentLanguage($localeTransfer);
153
154
        $postData = [
155
            'orderData' => $this->quoteDataMapper->mapQuoteDataByAllowedFields(
156
                $quoteTransfer,
157
                $this->paymentConfig->getQuoteFieldsForForeignPayment(),
158
            ),
159
            'redirectSuccessUrl' => $this->generatePaymentRedirectUrl(
160
                $language,
161
                $this->paymentConfig->getSuccessRoute(),
162
            ),
163
            'redirectCancelUrl' => $this->generatePaymentRedirectUrl(
164
                $language,
165
                $this->paymentConfig->getCancelRoute(),
166
                ['orderReference' => $quoteTransfer->getOrderReference()],
167
            ),
168
            'checkoutSummaryPageUrl' => $this->generatePaymentRedirectUrl(
169
                $language,
170
                $this->paymentConfig->getCheckoutSummaryPageRoute(),
171
            ),
172
        ];
173
174
        $acpHttpRequestTransfer = new AcpHttpRequestTransfer();
175
        $acpHttpRequestTransfer
176
            ->setMethod(Request::METHOD_POST)
177
            ->setUri($this->getAuthorizationEndpoint($paymentMethodTransfer))
178
            ->setBody((string)$this->utilEncodingService->encodeJson($postData));
179
180
        $acpHttpResponseTransfer = $this->kernelAppFacade->makeRequest($acpHttpRequestTransfer);
181
        $decodedResponseBody = $this->utilEncodingService->decodeJson($acpHttpResponseTransfer->getContentOrFail(), true);
182
183
        if ($acpHttpResponseTransfer->getHttpStatusCode() !== Response::HTTP_OK || json_last_error() !== JSON_ERROR_NONE) {
184
            $this->logAcpHttpResponseError($acpHttpRequestTransfer, $acpHttpResponseTransfer);
185
            $checkoutResponseTransfer
186
                ->setIsSuccess(false)
187
                ->addError($this->createCheckoutErrorTransfer($acpHttpResponseTransfer));
188
189
            return;
190
        }
191
192
        $paymentAuthorizeResponseTransfer = new PaymentAuthorizeResponseTransfer();
193
        $paymentAuthorizeResponseTransfer->fromArray((array)$decodedResponseBody, true);
194
195
        if (!$paymentAuthorizeResponseTransfer->getIsSuccessful()) {
196
            $this->logAcpHttpResponseError($acpHttpRequestTransfer, $acpHttpResponseTransfer);
197
198
            $checkoutResponseTransfer
199
                ->setIsSuccess(false)
200
                ->addError($this->createCheckoutErrorTransfer($acpHttpResponseTransfer));
201
202
            return;
203
        }
204
205
        if ($this->paymentConfig->getStoreFrontPaymentPage() === '') {
206
            $checkoutResponseTransfer
207
                ->setIsExternalRedirect(true)
208
                ->setRedirectUrl($paymentAuthorizeResponseTransfer->getRedirectUrl());
209
210
            return;
211
        }
212
213
        $redirectUrl = $this->addQueryParametersToUrl($this->paymentConfig->getStoreFrontPaymentPage(), [
214
            'url' => base64_encode($paymentAuthorizeResponseTransfer->getRedirectUrl()),
215
        ]);
216
217
        $checkoutResponseTransfer
218
            ->setIsExternalRedirect(true)
219
            ->setRedirectUrl($redirectUrl);
220
    }
221
222
    /**
223
     * @param \Generated\Shared\Transfer\PreOrderPaymentRequestTransfer $preOrderPaymentRequestTransfer
224
     *
225
     * @return \Generated\Shared\Transfer\PreOrderPaymentResponseTransfer
226
     */
227
    public function initializePreOrderPayment(
228
        PreOrderPaymentRequestTransfer $preOrderPaymentRequestTransfer
229
    ): PreOrderPaymentResponseTransfer {
230
        $quoteTransfer = $preOrderPaymentRequestTransfer->getQuoteOrFail();
231
232
        $paymentMethodTransfer = $this->paymentRepository->findPaymentMethod(
233
            $this->getPaymentMethodTransferFromRequestTransfer($preOrderPaymentRequestTransfer),
234
        );
235
236
        if (!$paymentMethodTransfer) {
237
            return (new PreOrderPaymentResponseTransfer())
238
                ->setIsSuccessful(false)
239
                ->setError('Payment method not found');
240
        }
241
242
        try {
243
            $url = $this->getAuthorizationEndpoint($paymentMethodTransfer);
244
        } catch (PreOrderPaymentException $e) {
245
            return (new PreOrderPaymentResponseTransfer())
246
                ->setIsSuccessful(false)
247
                ->setError($e->getMessage());
248
        }
249
250
        $postData = [
251
            'orderData' => $this->quoteDataMapper->mapQuoteDataByAllowedFields(
252
                $quoteTransfer,
253
                $this->paymentConfig->getQuoteFieldsForForeignPayment(),
254
            ),
255
            'preOrderPaymentData' => $preOrderPaymentRequestTransfer->getPreOrderPaymentData(),
256
            'localeName' => $this->localeFacade->getCurrentLocale()->getLocaleName(),
257
        ];
258
259
        // Workaround for cases when the PSP App is not updated and is using the paymentMethod property as name instead of the paymentMethodName property.
260
        if (!isset($postData['orderData']['paymentMethod'])) {
261
            $postData['orderData']['paymentMethod'] = $postData['orderData']['paymentMethodName'];
262
        }
263
264
        $acpHttpRequestTransfer = new AcpHttpRequestTransfer();
265
        $acpHttpRequestTransfer
266
            ->setMethod(Request::METHOD_POST)
267
            ->setUri($url)
268
            ->setBody((string)$this->utilEncodingService->encodeJson($postData));
269
270
        $acpHttpResponseTransfer = $this->kernelAppFacade->makeRequest($acpHttpRequestTransfer);
271
272
        // 200 Created is the expected response and only when we receive this it is successful
273
        $isSuccessful = $acpHttpResponseTransfer->getHttpStatusCode() === 200;
274
275
        $initializePreOrderPaymentResponseTransfer = new PreOrderPaymentResponseTransfer();
276
        $initializePreOrderPaymentResponseTransfer
277
            ->setIsSuccessful($isSuccessful);
278
279
        if (!$isSuccessful) {
280
            $initializePreOrderPaymentResponseTransfer->setError($acpHttpResponseTransfer->getContent());
281
282
            return $initializePreOrderPaymentResponseTransfer;
283
        }
284
285
        $decodedResponseBody = $this->utilEncodingService->decodeJson($acpHttpResponseTransfer->getContentOrFail(), true);
286
287
        if (json_last_error() !== JSON_ERROR_NONE) {
288
            $initializePreOrderPaymentResponseTransfer->setError($acpHttpResponseTransfer->getContentOrFail());
289
290
            return $initializePreOrderPaymentResponseTransfer;
291
        }
292
293
        if (!isset($decodedResponseBody[PaymentConfig::PRE_ORDER_PAYMENT_DATA_FIELD])) {
294
            $initializePreOrderPaymentResponseTransfer->setError('Response does not have the required preOrderPaymentData.');
295
296
            return $initializePreOrderPaymentResponseTransfer;
297
        }
298
299
        if (isset($decodedResponseBody['isSuccessful'])) {
300
            $initializePreOrderPaymentResponseTransfer->setIsSuccessful($decodedResponseBody['isSuccessful']);
301
302
            if ($decodedResponseBody['isSuccessful'] === false) {
303
                $initializePreOrderPaymentResponseTransfer->setError(sprintf('Request to payment provider failed. %s', $decodedResponseBody['message'] ?? ''));
304
305
                return $initializePreOrderPaymentResponseTransfer;
306
            }
307
        }
308
309
        $initializePreOrderPaymentResponseTransfer->setPreOrderPaymentData($decodedResponseBody[PaymentConfig::PRE_ORDER_PAYMENT_DATA_FIELD]);
310
311
        return $initializePreOrderPaymentResponseTransfer;
312
    }
313
314
    /**
315
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
316
     * @param \Generated\Shared\Transfer\CheckoutResponseTransfer $checkoutResponseTransfer
317
     *
318
     * @return void
319
     */
320
    public function confirmPreOrderPayment(
321
        QuoteTransfer $quoteTransfer,
322
        CheckoutResponseTransfer $checkoutResponseTransfer
323
    ): void {
324
        $paymentMethodTransfer = $this->paymentRepository->findPaymentMethod(
325
            (new PaymentMethodTransfer())
326
                ->setName($quoteTransfer->getPaymentOrFail()->getPaymentMethodOrFail())
327
                ->setPaymentProvider((new PaymentProviderTransfer())->setName($quoteTransfer->getPaymentOrFail()->getPaymentProviderOrFail())),
328
        );
329
330
        // Only foreign payment methods have a payment method app configuration. If it's not a foreign payment method, we can return early.
331
        if (!$paymentMethodTransfer || !$paymentMethodTransfer->getPaymentMethodAppConfiguration()) {
332
            return;
333
        }
334
335
        if (!$this->hasQuotePreOrderPaymentData($quoteTransfer) || !$this->isExpressCheckoutPaymentMethod($paymentMethodTransfer)) {
336
            return;
337
        }
338
339
        $saveOrderTransfer = $checkoutResponseTransfer->getSaveOrderOrFail();
340
341
        $orderData = $this->quoteDataMapper->mapQuoteDataByAllowedFields(
342
            $quoteTransfer,
343
            $this->paymentConfig->getQuoteFieldsForForeignPayment(),
344
        );
345
346
        $requestBody = [
347
            'orderReference' => $saveOrderTransfer->getOrderReference(),
348
            'orderData' => $orderData,
349
            PaymentConfig::PRE_ORDER_PAYMENT_DATA_FIELD => $quoteTransfer->getPreOrderPaymentData(),
350
            'localeName' => $this->localeFacade->getCurrentLocale()->getLocaleName(),
351
        ];
352
353
        $acpHttpRequestTransfer = new AcpHttpRequestTransfer();
354
        $acpHttpRequestTransfer
355
            ->setMethod(Request::METHOD_POST)
356
            ->setUri($this->getConfirmPreOrderPaymentEndpoint($paymentMethodTransfer))
357
            ->setBody((string)$this->utilEncodingService->encodeJson($requestBody));
358
359
        $acpHttpResponseTransfer = $this->kernelAppFacade->makeRequest($acpHttpRequestTransfer);
360
361
        if ($acpHttpResponseTransfer->getHttpStatusCode() !== Response::HTTP_OK) {
362
            $this->logAcpHttpResponseError($acpHttpRequestTransfer, $acpHttpResponseTransfer);
363
364
            $checkoutResponseTransfer
365
                ->addError((new CheckoutErrorTransfer())->setMessage(
366
                    sprintf(
367
                        'Failed to confirm pre-order payment for order %s. Response: %s',
368
                        $saveOrderTransfer->getOrderReference(),
369
                        $acpHttpResponseTransfer->getContent(),
370
                    ),
371
                ))
372
                ->setIsSuccess(false);
373
        }
374
    }
375
376
    /**
377
     * @param \Generated\Shared\Transfer\QuoteTransfer $quoteTransfer
378
     *
379
     * @return bool
380
     */
381
    protected function hasQuotePreOrderPaymentData(QuoteTransfer $quoteTransfer): bool
382
    {
383
        return count($quoteTransfer->getPreOrderPaymentData()) > 0;
384
    }
385
386
    /**
387
     * @param \Generated\Shared\Transfer\PaymentMethodTransfer $paymentMethodTransfer
388
     *
389
     * @return bool
390
     */
391
    protected function isExpressCheckoutPaymentMethod(PaymentMethodTransfer $paymentMethodTransfer): bool
392
    {
393
        $checkoutConfigurationTransfer = $paymentMethodTransfer->getPaymentMethodAppConfiguration()->getCheckoutConfiguration();
394
395
        return $checkoutConfigurationTransfer && $checkoutConfigurationTransfer->getStrategy() === PaymentConfig::CHECKOUT_STRATEGY_EXPRESS_CHECKOUT;
396
    }
397
398
    /**
399
     * @param \Generated\Shared\Transfer\PreOrderPaymentRequestTransfer $preOrderPaymentRequestTransfer
400
     *
401
     * @return \Generated\Shared\Transfer\PreOrderPaymentResponseTransfer
402
     */
403
    public function cancelPreOrderPayment(
404
        PreOrderPaymentRequestTransfer $preOrderPaymentRequestTransfer
405
    ): PreOrderPaymentResponseTransfer {
406
        $paymentMethodTransfer = $this->paymentRepository->findPaymentMethod(
407
            $this->getPaymentMethodTransferFromRequestTransfer($preOrderPaymentRequestTransfer),
408
        );
409
410
        if (!$paymentMethodTransfer) {
411
            return (new PreOrderPaymentResponseTransfer())
412
                ->setIsSuccessful(false)
413
                ->setError('Payment method not found');
414
        }
415
416
        $postData = [
417
            'preOrderPaymentData' => $preOrderPaymentRequestTransfer->getPreOrderPaymentData(),
418
        ];
419
420
        $acpHttpRequestTransfer = new AcpHttpRequestTransfer();
421
        $acpHttpRequestTransfer
422
            ->setMethod(Request::METHOD_POST)
423
            ->setUri($this->getCancelPreOrderPaymentEndpoint($paymentMethodTransfer))
424
            ->setBody((string)$this->utilEncodingService->encodeJson($postData));
425
426
        $acpHttpResponseTransfer = $this->kernelAppFacade->makeRequest($acpHttpRequestTransfer);
427
428
        // 200 Created is the expected response and only when we receive this it is successful
429
        $isSuccessful = $acpHttpResponseTransfer->getHttpStatusCode() === 200;
430
431
        $cancelPreOrderPaymentResponseTransfer = new PreOrderPaymentResponseTransfer();
432
        $cancelPreOrderPaymentResponseTransfer
433
            ->setIsSuccessful($isSuccessful);
434
435
        $decodedResponseBody = (array)$this->utilEncodingService->decodeJson($acpHttpResponseTransfer->getContentOrFail(), true);
436
437
        if (json_last_error() !== JSON_ERROR_NONE) {
438
            $cancelPreOrderPaymentResponseTransfer->setError($acpHttpResponseTransfer->getContentOrFail());
439
440
            return $cancelPreOrderPaymentResponseTransfer;
441
        }
442
443
        if (!$isSuccessful) {
444
            $cancelPreOrderPaymentResponseTransfer->setError($this->getMessageFromResponse($decodedResponseBody));
445
446
            return $cancelPreOrderPaymentResponseTransfer;
447
        }
448
449
        return $cancelPreOrderPaymentResponseTransfer;
450
    }
451
452
    /**
453
     * @param \Generated\Shared\Transfer\AcpHttpResponseTransfer $acpHttpResponseTransfer
454
     *
455
     * @return \Generated\Shared\Transfer\CheckoutErrorTransfer
456
     */
457
    protected function createCheckoutErrorTransfer(
458
        AcpHttpResponseTransfer $acpHttpResponseTransfer
459
    ): CheckoutErrorTransfer {
460
        return (new CheckoutErrorTransfer())
461
            ->setErrorCode(static::ERROR_MESSAGE_PAYMENT_FAILED)
462
            ->setMessage($this->paymentConfig->isDebugEnabled() ? $acpHttpResponseTransfer->getContent() : static::ERROR_MESSAGE_PAYMENT_AUTHORIZATION);
463
    }
464
465
    /**
466
     * @param \Generated\Shared\Transfer\AcpHttpRequestTransfer $acpHttpRequestTransfer
467
     * @param \Generated\Shared\Transfer\AcpHttpResponseTransfer $acpHttpResponseTransfer
468
     *
469
     * @return void
470
     */
471
    protected function logAcpHttpResponseError(
472
        AcpHttpRequestTransfer $acpHttpRequestTransfer,
473
        AcpHttpResponseTransfer $acpHttpResponseTransfer
474
    ): void {
475
        $this->getLogger()->error(
476
            static::ERROR_MESSAGE_PAYMENT_FAILED,
477
            [
478
                'payment_request' => $acpHttpRequestTransfer->toArray(),
479
                'response' => $acpHttpResponseTransfer->getContent(),
480
            ],
481
        );
482
    }
483
484
    /**
485
     * @param array<mixed> $response
486
     *
487
     * @return string
488
     */
489
    protected function getMessageFromResponse(array $response): string
490
    {
491
        if (isset($response['error'])) {
492
            return $response['error'];
493
        }
494
495
        if (isset($response[0]['message'])) {
496
            return $response[0]['message'];
497
        }
498
499
        return 'Response does not contain an error field.';
500
    }
501
502
    /**
503
     * @param \Generated\Shared\Transfer\PaymentMethodTransfer $paymentMethodTransfer
504
     *
505
     * @throws \Spryker\Zed\Payment\Business\Exception\PreOrderPaymentException
506
     *
507
     * @return string
508
     */
509
    protected function getAuthorizationEndpoint(PaymentMethodTransfer $paymentMethodTransfer): string
510
    {
511
        $paymentMethodAppConfigurationTransfer = $paymentMethodTransfer->getPaymentMethodAppConfiguration();
512
513
        if (!$paymentMethodAppConfigurationTransfer) {
514
            return $paymentMethodTransfer->getPaymentAuthorizationEndpoint();
515
        }
516
517
        $checkoutConfigurationTransfer = $paymentMethodAppConfigurationTransfer->getCheckoutConfiguration();
518
519
        $endpointName = PaymentConfig::PAYMENT_SERVICE_PROVIDER_ENDPOINT_NAME_AUTHORIZATION;
520
521
        if ($checkoutConfigurationTransfer && $checkoutConfigurationTransfer->getStrategy() === PaymentConfig::CHECKOUT_STRATEGY_EXPRESS_CHECKOUT) {
522
            $endpointName = PaymentConfig::PAYMENT_SERVICE_PROVIDER_ENDPOINT_NAME_PRE_ORDER_PAYMENT;
523
        }
524
525
        foreach ($paymentMethodAppConfigurationTransfer->getEndpoints() as $endpointTransfer) {
526
            if ($endpointTransfer->getNameOrFail() === $endpointName) {
527
                return sprintf('%s%s', $paymentMethodAppConfigurationTransfer->getBaseUrlOrFail(), $endpointTransfer->getPathOrFail());
528
            }
529
        }
530
531
        throw new PreOrderPaymentException(sprintf('Could not find an authorization endpoint for the payment method "%s". A reason for this could be that the Payment Apps configuration was not updated or not synced back.', $paymentMethodTransfer->getPaymentMethodKey()));
532
    }
533
534
    /**
535
     * @param \Generated\Shared\Transfer\PaymentMethodTransfer $paymentMethodTransfer
536
     *
537
     * @throws \Spryker\Zed\Payment\Business\Exception\PreOrderPaymentException
538
     *
539
     * @return string
540
     */
541
    protected function getConfirmPreOrderPaymentEndpoint(PaymentMethodTransfer $paymentMethodTransfer): string
542
    {
543
        $paymentMethodAppConfigurationTransfer = $paymentMethodTransfer->getPaymentMethodAppConfiguration();
544
545
        foreach ($paymentMethodAppConfigurationTransfer->getEndpoints() as $endpointTransfer) {
546
            if ($endpointTransfer->getNameOrFail() === PaymentConfig::PAYMENT_SERVICE_PROVIDER_ENDPOINT_NAME_PRE_ORDER_CONFIRMATION) {
547
                return sprintf('%s%s', $paymentMethodAppConfigurationTransfer->getBaseUrlOrFail(), $endpointTransfer->getPathOrFail());
548
            }
549
        }
550
551
        throw new PreOrderPaymentException(sprintf('Could not find an endpoint for pre-order payment confirmation of the payment method "%s". A reason for this could be that the Payment Apps configuration was not updated or not synced back.', $paymentMethodTransfer->getPaymentMethodKey()));
552
    }
553
554
    /**
555
     * @param \Generated\Shared\Transfer\PaymentMethodTransfer $paymentMethodTransfer
556
     *
557
     * @throws \Spryker\Zed\Payment\Business\Exception\PreOrderPaymentException
558
     *
559
     * @return string
560
     */
561
    protected function getCancelPreOrderPaymentEndpoint(PaymentMethodTransfer $paymentMethodTransfer): string
562
    {
563
        $paymentMethodAppConfigurationTransfer = $paymentMethodTransfer->getPaymentMethodAppConfiguration();
564
565
        foreach ($paymentMethodAppConfigurationTransfer->getEndpoints() as $endpointTransfer) {
566
            if ($endpointTransfer->getNameOrFail() === PaymentConfig::PAYMENT_SERVICE_PROVIDER_ENDPOINT_NAME_PRE_ORDER_CANCELLATION) {
567
                return sprintf('%s%s', $paymentMethodAppConfigurationTransfer->getBaseUrlOrFail(), $endpointTransfer->getPathOrFail());
568
            }
569
        }
570
571
        throw new PreOrderPaymentException(sprintf('Could not find an endpoint for pre-order payment cancellation of the payment method "%s". A reason for this could be that the Payment Apps configuration was not updated or not synced back.', $paymentMethodTransfer->getPaymentMethodKey()));
572
    }
573
574
    /**
575
     * @param string $language
576
     * @param string $urlPath
577
     * @param array<string, mixed> $queryParts
578
     *
579
     * @return string
580
     */
581
    protected function generatePaymentRedirectUrl(string $language, string $urlPath, array $queryParts = []): string
582
    {
583
        if ($this->isAbsoluteUrl($urlPath)) {
584
            return $this->addQueryParametersToUrl($urlPath, $queryParts);
585
        }
586
587
        $url = sprintf(
588
            '%s/%s%s',
589
            $this->paymentConfig->getBaseUrlYves(),
590
            $language,
591
            $urlPath,
592
        );
593
594
        return Url::generate($url, $queryParts)->build();
595
    }
596
597
    /**
598
     * @param string $url
599
     *
600
     * @return bool
601
     */
602
    protected function isAbsoluteUrl(string $url): bool
603
    {
604
        $urlComponents = parse_url($url);
605
606
        return isset($urlComponents['host']);
607
    }
608
609
    /**
610
     * @param string $url
611
     * @param array<string, mixed> $queryParams
612
     *
613
     * @return string
614
     */
615
    protected function addQueryParametersToUrl(string $url, array $queryParams): string
616
    {
617
        if ($queryParams === []) {
618
            return $url;
619
        }
620
621
        $urlComponents = parse_url($url);
622
623
        $url .= isset($urlComponents['query']) ? '&' : '?';
624
        $url .= http_build_query($queryParams);
625
626
        return $url;
627
    }
628
629
    /**
630
     * @param \Generated\Shared\Transfer\LocaleTransfer $localeTransfer
631
     *
632
     * @return string
633
     */
634
    protected function getCurrentLanguage(LocaleTransfer $localeTransfer): string
635
    {
636
        $splitLocale = explode('_', $localeTransfer->getLocaleNameOrFail());
637
638
        return $splitLocale[0];
639
    }
640
641
    /**
642
     * @param \Generated\Shared\Transfer\PreOrderPaymentRequestTransfer $preOrderPaymentRequestTransfer
643
     *
644
     * @return \Generated\Shared\Transfer\PaymentMethodTransfer
645
     */
646
    protected function getPaymentMethodTransferFromRequestTransfer(
647
        PreOrderPaymentRequestTransfer $preOrderPaymentRequestTransfer
648
    ): PaymentMethodTransfer {
649
        $paymentTransfer = $preOrderPaymentRequestTransfer->getPaymentOrFail();
650
651
        $paymentMethodName = $paymentTransfer->getPaymentMethod() ?? $paymentTransfer->getPaymentMethodName();
652
        $paymentProviderName = $paymentTransfer->getPaymentProvider() ?? $paymentTransfer->getPaymentProviderName();
653
654
        $paymentProviderTransfer = new PaymentProviderTransfer();
655
        $paymentProviderTransfer->setName($paymentTransfer->getPaymentProvider() ?? $paymentTransfer->getPaymentProviderName());
656
657
        $normalizedPaymentMethodKey = str_replace(' ', '-', mb_strtolower($paymentMethodName));
658
        $paymentMethodKey = sprintf('%s-%s', $paymentProviderName, $normalizedPaymentMethodKey);
659
660
        return (new PaymentMethodTransfer())
661
            ->setName($paymentMethodName)
662
            ->setPaymentMethodKey($paymentMethodKey)
663
            ->setPaymentProvider($paymentProviderTransfer);
664
    }
665
}
666