diff --git a/UPGRADE.md b/UPGRADE.md
index 76d821d5..4aa87617 100644
--- a/UPGRADE.md
+++ b/UPGRADE.md
@@ -1,3 +1,15 @@
+### UPGRADE FROM 1.3.0 to 1.3.1
+
+1. `sylius_paypal_plugin_pay_with_paypal_form` route now operates on both payment ID and order token. URl then changed from
+ `/pay-with-paypal/{id}` to `/pay-with-paypal/{orderToken}/{paymentId}`. If you use this route anywhere in your application, you
+ need to change the URL attributes
+
+### UPGRADE FROM 1.2.3 to 1.2.4
+
+1. `sylius_paypal_plugin_pay_with_paypal_form` route now operates on both payment ID and order token. URl then changed from
+ `/pay-with-paypal/{id}` to `/pay-with-paypal/{orderToken}/{paymentId}`. If you use this route anywhere in your application, you
+ need to change the URL attributes
+
### UPGRADE FROM 1.0.X TO 1.1.0
1. Upgrade your application to [Sylius 1.8](https://github.com/Sylius/Sylius/blob/master/UPGRADE-1.8.md).
diff --git a/phpstan.neon b/phpstan.neon
index 46e93df9..71b3ff4c 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -14,3 +14,6 @@ parameters:
# Test dependencies
- 'tests/Application/app/**.php'
- 'tests/Application/src/**.php'
+
+ ignoreErrors:
+ - '/Call to an undefined method Sylius\\Component\\Core\\Repository\\PaymentRepositoryInterface\:\:createQueryBuilder\(\)\./'
diff --git a/psalm.xml b/psalm.xml
index f38d221b..b117a394 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -12,6 +12,7 @@
+
diff --git a/spec/Payum/Action/ResolveNextRouteActionSpec.php b/spec/Payum/Action/ResolveNextRouteActionSpec.php
index a5a2362d..99a8ec61 100644
--- a/spec/Payum/Action/ResolveNextRouteActionSpec.php
+++ b/spec/Payum/Action/ResolveNextRouteActionSpec.php
@@ -17,6 +17,7 @@ final class ResolveNextRouteActionSpec extends ObjectBehavior
function it_executes_resolve_next_route_request_with_processing_payment(
ResolveNextRoute $request,
PaymentInterface $payment,
+ OrderInterface $order,
PaymentMethodInterface $paymentMethod,
GatewayConfigInterface $gatewayConfig
): void {
@@ -28,8 +29,11 @@ function it_executes_resolve_next_route_request_with_processing_payment(
$paymentMethod->getGatewayConfig()->willReturn($gatewayConfig);
$gatewayConfig->getFactoryName()->willReturn('sylius.pay_pal');
+ $payment->getOrder()->willReturn($order);
+ $order->getTokenValue()->willReturn('123!@#asd');
+
$request->setRouteName('sylius_paypal_plugin_pay_with_paypal_form')->shouldBeCalled();
- $request->setRouteParameters(['id' => 12])->shouldBeCalled();
+ $request->setRouteParameters(['orderToken' => '123!@#asd', 'paymentId' => 12])->shouldBeCalled();
$this->execute($request);
}
@@ -37,10 +41,12 @@ function it_executes_resolve_next_route_request_with_processing_payment(
function it_executes_resolve_next_route_request_with_completed_payment(
ResolveNextRoute $request,
PaymentInterface $payment,
+ OrderInterface $order,
PaymentMethodInterface $paymentMethod,
GatewayConfigInterface $gatewayConfig
): void {
$request->getFirstModel()->willReturn($payment);
+ $payment->getOrder()->willReturn($order);
$payment->getState()->willReturn(PaymentInterface::STATE_COMPLETED);
$payment->getMethod()->willReturn($paymentMethod);
diff --git a/src/Controller/PayWithPayPalFormAction.php b/src/Controller/PayWithPayPalFormAction.php
index d1c13888..4bac1a14 100644
--- a/src/Controller/PayWithPayPalFormAction.php
+++ b/src/Controller/PayWithPayPalFormAction.php
@@ -44,8 +44,11 @@ public function __construct(
public function __invoke(Request $request): Response
{
+ $paymentId = (string) $request->attributes->get('paymentId');
+ $orderToken = (string) $request->attributes->get('orderToken');
+
/** @var PaymentInterface $payment */
- $payment = $this->paymentRepository->find($request->attributes->get('id'));
+ $payment = $this->findOneByPaymentIdOrderToken($paymentId, $orderToken);
/** @var PaymentMethodInterface $paymentMethod */
$paymentMethod = $payment->getMethod();
@@ -74,4 +77,22 @@ public function __invoke(Request $request): Response
'partner_attribution_id' => $partnerAttributionId,
]));
}
+
+ /**
+ * Need to be used due to support for Sylius 1.8.
+ * After dropping it, we can switch to Sylius\Component\Core\Repository\PaymentRepositoryInterface::findOneByOrderToken
+ */
+ private function findOneByPaymentIdOrderToken(string $paymentId, string $orderToken): ?PaymentInterface
+ {
+ return $this->paymentRepository
+ ->createQueryBuilder('p')
+ ->innerJoin('p.order', 'o')
+ ->andWhere('p.id = :paymentId')
+ ->andWhere('o.tokenValue = :orderToken')
+ ->setParameter('paymentId', $paymentId)
+ ->setParameter('orderToken', $orderToken)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
}
diff --git a/src/Payum/Action/ResolveNextRouteAction.php b/src/Payum/Action/ResolveNextRouteAction.php
index a7ed2c72..30f6d80a 100644
--- a/src/Payum/Action/ResolveNextRouteAction.php
+++ b/src/Payum/Action/ResolveNextRouteAction.php
@@ -19,9 +19,14 @@ public function execute($request): void
/** @var PaymentInterface $payment */
$payment = $request->getFirstModel();
+ /** @var OrderInterface $order */
+ $order = $payment->getOrder();
+
if ($payment->getState() === PaymentInterface::STATE_NEW) {
$request->setRouteName('sylius_paypal_plugin_pay_with_paypal_form');
- $request->setRouteParameters(['id' => $payment->getId()]);
+ $request->setRouteParameters(
+ ['orderToken' => $order->getTokenValue(), 'paymentId' => $payment->getId()]
+ );
return;
}
@@ -32,9 +37,6 @@ public function execute($request): void
return;
}
- /** @var OrderInterface $order */
- $order = $payment->getOrder();
-
$request->setRouteName('sylius_shop_order_show');
$request->setRouteParameters(['tokenValue' => $order->getTokenValue()]);
}
diff --git a/src/Resources/config/shop_routing.yaml b/src/Resources/config/shop_routing.yaml
index 835c8ed1..7310c157 100644
--- a/src/Resources/config/shop_routing.yaml
+++ b/src/Resources/config/shop_routing.yaml
@@ -1,5 +1,5 @@
sylius_paypal_plugin_pay_with_paypal_form:
- path: /pay-with-paypal/{id}
+ path: /pay-with-paypal/{orderToken}/{paymentId}
methods: [GET]
defaults:
_controller: Sylius\PayPalPlugin\Controller\PayWithPayPalFormAction
diff --git a/src/Resources/views/payWithPaypal.html.twig b/src/Resources/views/payWithPaypal.html.twig
index ef09d17a..e164e4d1 100644
--- a/src/Resources/views/payWithPaypal.html.twig
+++ b/src/Resources/views/payWithPaypal.html.twig
@@ -329,6 +329,8 @@
});
if (paypal.HostedFields.isEligible() === true) {
+ let processingOrderId;
+
paypal.HostedFields.render({
createOrder: function(data, actions) {
document.querySelector('#paypal-payment-container').classList.add('loading');
@@ -339,6 +341,8 @@
}).then(function(res) {
return res.json();
}).then(function(data) {
+ processingOrderId = data.orderID;
+
return data.orderID;
});
},
@@ -419,6 +423,7 @@
if (formValid) {
hostedFields.submit({
+ contingencies: ['SCA_ALWAYS'],
cardholderName: document.getElementById('card-holder-name').value,
billingAddress: {
streetAddress: document.getElementById('card-billing-address-street').value,
@@ -428,20 +433,35 @@
countryCodeAlpha2: document.getElementById('card-billing-address-country').value
}
}).then(payload => {
- return fetch(completePayPalOrderUrl, {
- method: 'post'
- }).then(function(res) {
- return res.json();
+ if (payload.authenticationReason == 'SUCCESSFUL' && payload.authenticationStatus == 'YES') {
+ return fetch(completePayPalOrderUrl, {
+ method: 'post'
+ }).then(function(res) {
+ return res.json();
+ }).then(function(data) {
+ if (data.status == 'processing') {
+ return fetch(cancelPayPalPaymentUrl, {
+ method: 'post',
+ headers: { 'content-type': 'application/json' },
+ body: JSON.stringify({ payPalOrderId: data.orderID })
+ }).then(window.location.reload());
+ }
+
+ window.location.href = data.return_url;
+ });
+ }
+
+
+ return fetch(errorPayPalPaymentUrl, {
+ method: 'post',
+ headers: { 'content-type': 'application/json' },
+ body: JSON.stringify('Invalid 3D Secure authentication.')
}).then(function(data) {
- if (data.status == 'processing') {
- return fetch(cancelPayPalPaymentUrl, {
- method: 'post',
- headers: { 'content-type': 'application/json' },
- body: JSON.stringify({ payPalOrderId: data.orderID })
- }).then(window.location.reload());
- }
-
- window.location.href = data.return_url;
+ return fetch(cancelPayPalPaymentUrl, {
+ method: 'post',
+ headers: { 'content-type': 'application/json' },
+ body: JSON.stringify({ payPalOrderId: processingOrderId })
+ }).then(window.location.reload());
});
});
} else {