Skip to content

Commit b8564bf

Browse files
committed
Merge remote-tracking branch 'origin/MC-17118-payflow-link' into payflow-graphql-pr
2 parents 9b8849d + 39cc246 commit b8564bf

16 files changed

+1349
-9
lines changed

app/code/Magento/Paypal/Model/Payflowlink.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ protected function _buildTokenRequest(\Magento\Sales\Model\Order\Payment $paymen
425425
$request->setCreatesecuretoken('Y')
426426
->setSecuretokenid($this->mathRandom->getUniqueHash())
427427
->setTrxtype($this->_getTrxTokenType());
428+
$request = $this->updateRequestReturnUrls($request, $payment);
428429

429430
$order = $payment->getOrder();
430431
$request->setAmt(sprintf('%.2F', $order->getBaseTotalDue()))
@@ -440,8 +441,7 @@ protected function _buildTokenRequest(\Magento\Sales\Model\Order\Payment $paymen
440441
}
441442

442443
/**
443-
* Get store id from response if exists
444-
* or default
444+
* Get store id from response if exists or default
445445
*
446446
* @return int
447447
*/
@@ -464,7 +464,6 @@ public function buildBasicRequest()
464464
/** @var \Magento\Paypal\Model\Payflow\Request $request */
465465
$request = $this->_requestFactory->create();
466466
$cscEditable = $this->getConfigData('csc_editable');
467-
468467
$data = parent::buildBasicRequest();
469468

470469
$request->setData($data->getData());
@@ -514,6 +513,7 @@ protected function _getTrxTokenType()
514513

515514
/**
516515
* If response is failed throw exception
516+
*
517517
* Set token data in payment object
518518
*
519519
* @param \Magento\Framework\DataObject $response
@@ -558,6 +558,7 @@ protected function _getSecureSilentPostHash($payment)
558558
*/
559559
protected function _generateSecureSilentPostHash($payment)
560560
{
561+
//phpcs:ignore Magento2.Security.InsecureFunction
561562
$secureHash = md5($this->mathRandom->getRandomString(10));
562563
$payment->setAdditionalInformation($this->_secureSilentPostHashKey, $secureHash);
563564
return $secureHash;
@@ -600,4 +601,30 @@ protected function _getCallbackUrl($actionName)
600601

601602
return $websiteUrl . 'paypal/' . $this->_callbackController . '/' . $actionName;
602603
}
604+
605+
/**
606+
* Update the redirect urls on the request if they are set on the payment
607+
*
608+
* @param \Magento\Paypal\Model\Payflow\Request $request
609+
* @param \Magento\Sales\Model\Order\Payment $payment
610+
* @return \Magento\Paypal\Model\Payflow\Request
611+
*/
612+
private function updateRequestReturnUrls(
613+
\Magento\Paypal\Model\Payflow\Request $request,
614+
\Magento\Sales\Model\Order\Payment $payment
615+
): \Magento\Paypal\Model\Payflow\Request {
616+
$paymentData = $payment->getAdditionalInformation();
617+
618+
if (!empty($paymentData['cancel_url'])) {
619+
$request->setCancelurl($paymentData['cancel_url']);
620+
}
621+
if (!empty($paymentData['return_url'])) {
622+
$request->setReturnurl($paymentData['return_url']);
623+
}
624+
if (!empty($paymentData['error_url'])) {
625+
$request->setErrorurl($paymentData['error_url']);
626+
}
627+
628+
return $request;
629+
}
603630
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\PaypalGraphQl\Model;
9+
10+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
11+
use Magento\Framework\Url\Validator as UrlValidator;
12+
use Magento\Paypal\Model\Config;
13+
use Magento\QuoteGraphQl\Model\Cart\Payment\AdditionalDataProviderInterface;
14+
15+
/**
16+
* Get payment additional data for Paypal Payflow Link payment
17+
*/
18+
class PayflowLinkAdditionalDataProvider implements AdditionalDataProviderInterface
19+
{
20+
/**
21+
* @var UrlValidator
22+
*/
23+
private $urlValidator;
24+
25+
/**
26+
* @param UrlValidator $urlValidator
27+
*/
28+
public function __construct(UrlValidator $urlValidator)
29+
{
30+
$this->urlValidator = $urlValidator;
31+
}
32+
33+
/**
34+
* Returns additional data
35+
*
36+
* @param array $data
37+
* @return array
38+
* @throws GraphQlInputException
39+
*/
40+
public function getData(array $data): array
41+
{
42+
$additionalData = $data[Config::METHOD_PAYFLOWLINK] ?? [];
43+
$this->validateUrls($additionalData);
44+
45+
return $additionalData;
46+
}
47+
48+
/**
49+
* Validate redirect urls
50+
*
51+
* @param array $data
52+
* @throws GraphQlInputException
53+
*/
54+
private function validateUrls(array $data): void
55+
{
56+
$urlKeys = ['cancel_url', 'return_url', 'error_url'];
57+
58+
foreach ($urlKeys as $urlKey) {
59+
if (isset($data[$urlKey])) {
60+
if (!$this->urlValidator->isValid($data[$urlKey])) {
61+
$errorMessage = $this->urlValidator->getMessages()['invalidUrl'] ?? "Invalid Url.";
62+
throw new GraphQlInputException(__($errorMessage));
63+
}
64+
}
65+
}
66+
}
67+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\PaypalGraphQl\Model\Resolver;
9+
10+
use Magento\Framework\Exception\NoSuchEntityException;
11+
use Magento\Framework\GraphQl\Config\Element\Field;
12+
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
13+
use Magento\Framework\GraphQl\Query\ResolverInterface;
14+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
15+
use Magento\Payment\Helper\Data as PaymentDataHelper;
16+
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
17+
use Magento\Sales\Model\Order\Payment;
18+
use Magento\Sales\Model\Order;
19+
use Magento\Store\Model\StoreManagerInterface;
20+
use Magento\Sales\Model\ResourceModel\Order\CollectionFactoryInterface;
21+
22+
/**
23+
* Resolver to pull PayflowLink payment information from pending order
24+
*/
25+
class PayflowLinkToken implements ResolverInterface
26+
{
27+
/**
28+
* @var MaskedQuoteIdToQuoteIdInterface
29+
*/
30+
private $maskedQuoteIdToQuoteId;
31+
32+
/**
33+
* @var PaymentDataHelper
34+
*/
35+
private $paymentDataHelper;
36+
37+
/**
38+
* @var StoreManagerInterface
39+
*/
40+
private $storeManager;
41+
42+
/**
43+
* @var CollectionFactoryInterface
44+
*/
45+
private $orderCollectionFactory;
46+
47+
/**
48+
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
49+
* @param PaymentDataHelper $paymentDataHelper
50+
* @param StoreManagerInterface $storeManager
51+
* @param CollectionFactoryInterface $orderCollectionFactory
52+
*/
53+
public function __construct(
54+
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
55+
PaymentDataHelper $paymentDataHelper,
56+
StoreManagerInterface $storeManager,
57+
CollectionFactoryInterface $orderCollectionFactory
58+
) {
59+
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
60+
$this->paymentDataHelper = $paymentDataHelper;
61+
$this->storeManager = $storeManager;
62+
$this->orderCollectionFactory = $orderCollectionFactory;
63+
}
64+
65+
/**
66+
* @inheritdoc
67+
*/
68+
public function resolve(
69+
Field $field,
70+
$context,
71+
ResolveInfo $info,
72+
array $value = null,
73+
array $args = null
74+
) {
75+
$customerId = $context->getUserId();
76+
$maskedCartId = $args['input']['cart_id'] ?? '';
77+
try {
78+
$cartId = $this->maskedQuoteIdToQuoteId->execute($maskedCartId);
79+
} catch (NoSuchEntityException $e) {
80+
throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
81+
}
82+
83+
$order = $this->getOrderFromQuoteId($cartId, $customerId);
84+
$payment = $order->getPayment();
85+
$paymentAdditionalInformation = $payment->getAdditionalInformation();
86+
87+
return [
88+
'mode' => $this->getPaymentMode($payment),
89+
'paypal_url' => $this->getPayflowLinkUrl($payment),
90+
'secret_token' => $paymentAdditionalInformation['secure_token'],
91+
'secret_token_id' => $paymentAdditionalInformation['secure_token_id'],
92+
];
93+
}
94+
95+
/**
96+
* Retrieve an order from its corresponding quote id
97+
*
98+
* @param int $quoteId
99+
* @param int $customerId
100+
* @return Order
101+
* @throws GraphQlNoSuchEntityException
102+
*/
103+
private function getOrderFromQuoteId(int $quoteId, int $customerId): Order
104+
{
105+
$storeId = (int)$this->storeManager->getStore()->getId();
106+
107+
$orderCollection = $this->orderCollectionFactory->create($customerId ?? null);
108+
$orderCollection->addFilter(Order::QUOTE_ID, $quoteId);
109+
$orderCollection->addFilter(Order::STATUS, Order::STATE_PENDING_PAYMENT);
110+
$orderCollection->addFilter(Order::STORE_ID, $storeId);
111+
112+
if ($orderCollection->getTotalCount() !== 1) {
113+
throw new GraphQlNoSuchEntityException(__('Could not find payment information for cart.'));
114+
}
115+
/** @var Order $order */
116+
$order = $orderCollection->getFirstItem();
117+
118+
return $order;
119+
}
120+
121+
/**
122+
* Get payment mode based on sandbox flag
123+
*
124+
* @param Payment $payment
125+
* @return string
126+
*/
127+
private function getPaymentMode(Payment $payment): string
128+
{
129+
$sandboxFlag = $this->paymentDataHelper
130+
->getMethodInstance($payment->getMethod())
131+
->getConfigData('sandbox_flag');
132+
133+
return $sandboxFlag ? 'TEST' : 'LIVE';
134+
}
135+
136+
/**
137+
* Get Payflow Link url
138+
*
139+
* @param Payment $payment
140+
* @return string
141+
*/
142+
private function getPayflowLinkUrl(Payment $payment): string
143+
{
144+
$configField = 'cgi_url';
145+
if ($this->getPaymentMode($payment) === 'TEST') {
146+
$configField = 'cgi_url_test_mode';
147+
}
148+
149+
return $this->paymentDataHelper->getMethodInstance($payment->getMethod())->getConfigData($configField);
150+
}
151+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\PaypalGraphQl\Observer;
9+
10+
use Magento\Framework\Event\Observer;
11+
use Magento\Payment\Observer\AbstractDataAssignObserver;
12+
use Magento\Quote\Api\Data\PaymentInterface;
13+
14+
/**
15+
* Set additional data for payflow link payment
16+
*/
17+
class PayflowLinkSetAdditionalData extends AbstractDataAssignObserver
18+
{
19+
/**
20+
* @inheritdoc
21+
*/
22+
public function execute(Observer $observer): void
23+
{
24+
$dataObject = $this->readDataArgument($observer);
25+
26+
$additionalData = $dataObject->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
27+
if (!is_array($additionalData)) {
28+
return;
29+
}
30+
31+
$paymentModel = $this->readPaymentModelArgument($observer);
32+
$paymentModel->setAdditionalInformation($additionalData);
33+
}
34+
}

app/code/Magento/PaypalGraphQl/composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
"magento/module-quote": "*",
1111
"magento/module-checkout": "*",
1212
"magento/module-paypal": "*",
13-
"magento/module-quote-graph-ql": "*"
13+
"magento/module-quote-graph-ql": "*",
14+
"magento/module-sales": "*",
15+
"magento/module-payment": "*",
16+
"magento/module-store": "*"
1417
},
1518
"suggest": {
1619
"magento/module-graph-ql": "*"

app/code/Magento/PaypalGraphQl/etc/graphql/di.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,12 @@
3636
</argument>
3737
</arguments>
3838
</type>
39+
40+
<type name="Magento\QuoteGraphQl\Model\Cart\Payment\AdditionalDataProviderPool">
41+
<arguments>
42+
<argument name="dataProviders" xsi:type="array">
43+
<item name="payflow_link" xsi:type="object">Magento\PaypalGraphQl\Model\PayflowLinkAdditionalDataProvider</item>
44+
</argument>
45+
</arguments>
46+
</type>
3947
</config>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
9+
<event name="payment_method_assign_data_payflow_link">
10+
<observer name="payflow_link_data_assigner" instance="Magento\PaypalGraphQl\Observer\PayflowLinkSetAdditionalData"/>
11+
</event>
12+
</config>

0 commit comments

Comments
 (0)