diff --git a/spec/Processor/PayPalOrderCompleteProcessorSpec.php b/spec/Processor/PayPalOrderCompleteProcessorSpec.php index 32d1d2a7..32e989ba 100644 --- a/spec/Processor/PayPalOrderCompleteProcessorSpec.php +++ b/spec/Processor/PayPalOrderCompleteProcessorSpec.php @@ -20,12 +20,15 @@ use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\PayPalPlugin\Manager\PaymentStateManagerInterface; +use Sylius\PayPalPlugin\Verifier\PaymentAmountVerifierInterface; final class PayPalOrderCompleteProcessorSpec extends ObjectBehavior { - function let(PaymentStateManagerInterface $paymentStateManager): void - { - $this->beConstructedWith($paymentStateManager); + function let( + PaymentStateManagerInterface $paymentStateManager, + PaymentAmountVerifierInterface $paymentAmountVerifier, + ): void { + $this->beConstructedWith($paymentStateManager, $paymentAmountVerifier); } function it_completes_pay_pal_order( @@ -34,12 +37,14 @@ function it_completes_pay_pal_order( PaymentInterface $payment, PaymentMethodInterface $paymentMethod, GatewayConfigInterface $gatewayConfig, + PaymentAmountVerifierInterface $paymentAmountVerifier, ): void { $order->getLastPayment(PaymentInterface::STATE_PROCESSING)->willReturn($payment); $payment->getMethod()->willReturn($paymentMethod); $paymentMethod->getGatewayConfig()->willReturn($gatewayConfig); $gatewayConfig->getFactoryName()->willReturn('sylius.pay_pal'); + $paymentAmountVerifier->verify($payment)->shouldBeCalled(); $paymentStateManager->complete($payment)->shouldBeCalled(); diff --git a/src/Processor/PayPalOrderCompleteProcessor.php b/src/Processor/PayPalOrderCompleteProcessor.php index 5eaaaf22..9ee7d786 100644 --- a/src/Processor/PayPalOrderCompleteProcessor.php +++ b/src/Processor/PayPalOrderCompleteProcessor.php @@ -17,15 +17,24 @@ use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; +use Sylius\PayPalPlugin\Exception\PaymentAmountMismatchException; use Sylius\PayPalPlugin\Manager\PaymentStateManagerInterface; +use Sylius\PayPalPlugin\Verifier\PaymentAmountVerifierInterface; final class PayPalOrderCompleteProcessor { - private PaymentStateManagerInterface $paymentStateManager; - - public function __construct(PaymentStateManagerInterface $paymentStateManager) - { - $this->paymentStateManager = $paymentStateManager; + public function __construct( + private PaymentStateManagerInterface $paymentStateManager, + private ?PaymentAmountVerifierInterface $paymentAmountVerifier = null, + ) { + if (null === $this->paymentAmountVerifier) { + trigger_deprecation( + 'sylius/paypal-plugin', + '1.6', + 'Not passing an instance of "%s" as the second argument is deprecated and will be prohibited in 3.0.', + PaymentAmountVerifierInterface::class, + ); + } } public function completePayPalOrder(OrderInterface $order): void @@ -44,6 +53,34 @@ public function completePayPalOrder(OrderInterface $order): void return; } + try { + if (null !== $this->paymentAmountVerifier) { + $this->paymentAmountVerifier->verify($payment); + } else { + $this->verify($payment); + } + } catch (PaymentAmountMismatchException) { + $this->paymentStateManager->cancel($payment); + + return; + } + $this->paymentStateManager->complete($payment); } + + private function verify(PaymentInterface $payment): void + { + $totalAmount = $this->getTotalPaymentAmountFromPaypal($payment); + + if ($payment->getOrder()->getTotal() !== $totalAmount) { + throw new PaymentAmountMismatchException(); + } + } + + private function getTotalPaymentAmountFromPaypal(PaymentInterface $payment): int + { + $details = $payment->getDetails(); + + return $details['payment_amount'] ?? 0; + } } diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index b32c7a7d..a844d612 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -132,6 +132,7 @@ +