Skip to content

Commit

Permalink
fix(PT-13134): Prevent call create order with an empty cart
Browse files Browse the repository at this point in the history
  • Loading branch information
DennisGarding committed Sep 21, 2023
1 parent dc8aefe commit afc1e35
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 7 deletions.
19 changes: 19 additions & 0 deletions Controllers/Frontend/AbstractPaypalPaymentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\CaptureDeclinedException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\CaptureFailedException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\CapturePendingException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\EmptyCartException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InstrumentDeclinedException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidBillingAddressException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidShippingAddressException;
Expand Down Expand Up @@ -226,6 +227,10 @@ protected function createPayPalOrder(PayPalOrderParameter $orderParameter)
try {
$this->logger->debug(sprintf('%s BEFORE CREATE PAYPAL ORDER', __METHOD__));

if (empty($orderParameter->getCart()['content'])) {
throw new EmptyCartException();
}

$payPalOrderData = $this->orderFactory->createOrder($orderParameter);

$payPalOrder = $this->orderResource->create($payPalOrderData, $orderParameter->getPaymentType());
Expand Down Expand Up @@ -259,6 +264,8 @@ protected function createPayPalOrder(PayPalOrderParameter $orderParameter)
return null;
} catch (PuiValidationException $puiValidationException) {
throw $puiValidationException;
} catch (EmptyCartException $emptyCartException) {
throw $emptyCartException;
} catch (Exception $exception) {
$redirectDataBuilder = $this->redirectDataBuilderFactory->createRedirectDataBuilder()
->setCode(ErrorCodes::UNKNOWN)
Expand Down Expand Up @@ -861,6 +868,18 @@ protected function getInvalidAddressUrl(array $error)
], $error));
}

/**
* @return string
*/
protected function getEmptyCartErrorUrl()
{
return $this->dependencyProvider->getRouter()->assemble([
'module' => 'frontend',
'controller' => 'checkout',
'action' => 'cart',
]);
}

/**
* @return bool
*/
Expand Down
19 changes: 19 additions & 0 deletions Controllers/Frontend/Exceptions/EmptyCartException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
/**
* (c) shopware AG <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions;

use Exception;

class EmptyCartException extends Exception
{
public function __construct()
{
parent::__construct('Cannot create a PayPal order with an empty cart');
}
}
9 changes: 9 additions & 0 deletions Controllers/Frontend/PaypalUnifiedApm.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use SwagPaymentPayPalUnified\Components\ErrorCodes;
use SwagPaymentPayPalUnified\Components\PayPalOrderParameter\ShopwareOrderData;
use SwagPaymentPayPalUnified\Controllers\Frontend\AbstractPaypalPaymentController;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\EmptyCartException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidBillingAddressException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidShippingAddressException;
use SwagPaymentPayPalUnified\PayPalBundle\V2\Api\Common\Link;
Expand Down Expand Up @@ -69,6 +70,14 @@ public function indexAction()
} catch (InvalidShippingAddressException $invalidShippingAddressException) {
$this->redirectInvalidAddress(['invalidShippingAddress' => true]);

return;
} catch (EmptyCartException $emptyCartException) {
$this->redirect([
'module' => 'frontend',
'controller' => 'checkout',
'action' => 'cart',
]);

return;
}

Expand Down
6 changes: 6 additions & 0 deletions Controllers/Frontend/PaypalUnifiedV2.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use SwagPaymentPayPalUnified\Components\ErrorCodes;
use SwagPaymentPayPalUnified\Components\PayPalOrderParameter\ShopwareOrderData;
use SwagPaymentPayPalUnified\Controllers\Frontend\AbstractPaypalPaymentController;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\EmptyCartException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InstrumentDeclinedException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidBillingAddressException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidShippingAddressException;
Expand Down Expand Up @@ -87,6 +88,11 @@ public function indexAction()
$this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST);
$this->view->assign('redirectTo', $this->getInvalidAddressUrl(['invalidShippingAddress' => true]));

return;
} catch (EmptyCartException $emptyCartException) {
$this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST);
$this->view->assign('redirectTo', $this->getEmptyCartErrorUrl());

return;
}

Expand Down
9 changes: 9 additions & 0 deletions Controllers/Frontend/PaypalUnifiedV2PayUponInvoice.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use SwagPaymentPayPalUnified\Components\Exception\PuiValidationException;
use SwagPaymentPayPalUnified\Components\PayPalOrderParameter\ShopwareOrderData;
use SwagPaymentPayPalUnified\Controllers\Frontend\AbstractPaypalPaymentController;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\EmptyCartException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidBillingAddressException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidShippingAddressException;
use SwagPaymentPayPalUnified\PayPalBundle\PaymentType;
Expand Down Expand Up @@ -78,6 +79,14 @@ public function indexAction()
} catch (InvalidShippingAddressException $invalidShippingAddressException) {
$this->redirectInvalidAddress(['invalidShippingAddress' => true]);

return;
} catch (EmptyCartException $emptyCartException) {
$this->redirect([
'module' => 'frontend',
'controller' => 'checkout',
'action' => 'cart',
]);

return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use SwagPaymentPayPalUnified\Components\Services\ThreeDSecureResultChecker\Exception\ThreeDSecureCardHasNoAuthorization;
use SwagPaymentPayPalUnified\Components\Services\ThreeDSecureResultChecker\ThreeDSecureResultChecker;
use SwagPaymentPayPalUnified\Controllers\Frontend\AbstractPaypalPaymentController;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\EmptyCartException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InstrumentDeclinedException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidBillingAddressException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidShippingAddressException;
Expand Down Expand Up @@ -93,6 +94,11 @@ public function createOrderAction()
$this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST);
$this->view->assign('redirectTo', $this->getInvalidAddressUrl(['invalidShippingAddress' => true]));

return;
} catch (EmptyCartException $emptyCartException) {
$this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST);
$this->view->assign('redirectTo', $this->getEmptyCartErrorUrl());

return;
}

Expand Down
6 changes: 6 additions & 0 deletions Controllers/Widgets/PaypalUnifiedV2SmartPaymentButtons.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use SwagPaymentPayPalUnified\Components\ErrorCodes;
use SwagPaymentPayPalUnified\Components\PayPalOrderParameter\ShopwareOrderData;
use SwagPaymentPayPalUnified\Controllers\Frontend\AbstractPaypalPaymentController;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\EmptyCartException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidBillingAddressException;
use SwagPaymentPayPalUnified\Controllers\Frontend\Exceptions\InvalidShippingAddressException;
use SwagPaymentPayPalUnified\PayPalBundle\PaymentType;
Expand Down Expand Up @@ -70,6 +71,11 @@ public function createOrderAction()
$this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST);
$this->view->assign('redirectTo', $this->getInvalidAddressUrl(['invalidShippingAddress' => true]));

return;
} catch (EmptyCartException $emptyCartException) {
$this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST);
$this->view->assign('redirectTo', $this->getEmptyCartErrorUrl());

return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php
/**
* (c) shopware AG <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SwagPaymentPayPalUnified\Tests\Functional\Controller\Frontend;

use Enlight_Controller_Action;
use Enlight_Controller_Response_ResponseHttp;
use Generator;
use Shopware_Controllers_Frontend_PaypalUnifiedApm;
use Shopware_Controllers_Frontend_PaypalUnifiedV2;
use Shopware_Controllers_Frontend_PaypalUnifiedV2PayUponInvoice;
use Shopware_Controllers_Widgets_PaypalUnifiedV2AdvancedCreditDebitCard;
use Shopware_Controllers_Widgets_PaypalUnifiedV2SmartPaymentButtons;
use SwagPaymentPayPalUnified\Tests\Functional\AssertLocationTrait;
use SwagPaymentPayPalUnified\Tests\Functional\ContainerTrait;
use SwagPaymentPayPalUnified\Tests\Functional\ShopRegistrationTrait;
use SwagPaymentPayPalUnified\Tests\Unit\PaypalPaymentControllerTestCase;

class AbstractPayPalPaymentControllerThrowsExceptionOnCreateOrderWithEmptyCartTest extends PaypalPaymentControllerTestCase
{
use ContainerTrait;
use ShopRegistrationTrait;
use AssertLocationTrait;

/**
* @dataProvider createPayPalOrderShouldThrowExceptionWithEmptyCartDataProvider
*
* @param class-string<Enlight_Controller_Action> $controllerClass
* @param string $actionName
*
* @return void
*/
public function testCreatePayPalOrderShouldThrowExceptionWithEmptyCart($controllerClass, $actionName, bool $shouldAssignToView)
{
$sOrderVariables = [
'sUserData' => require __DIR__ . '/_fixtures/getUser_result.php',
'sBasket' => ['content' => []],
];

$session = $this->getContainer()->get('session');
$session->set('sOrderVariables', $sOrderVariables);

$controller = $this->getController(
$controllerClass,
[
self::SERVICE_DEPENDENCY_PROVIDER => $this->getContainer()->get('paypal_unified.dependency_provider'),
self::SERVICE_ORDER_PARAMETER_FACADE => $this->getContainer()->get('paypal_unified.paypal_order_parameter_facade'),
],
null,
new Enlight_Controller_Response_ResponseHttp()
);

$controller->$actionName();

if ($shouldAssignToView) {
$result = $controller->View()->getAssign('redirectTo');

static::assertStringEndsWith('checkout/cart', $result);

return;
}

static::assertLocationEndsWith($controller->Response(), 'checkout/cart');
}

/**
* @return Generator<array<int,mixed>>
*/
public function createPayPalOrderShouldThrowExceptionWithEmptyCartDataProvider()
{
yield 'Shopware_Controllers_Frontend_PaypalUnifiedV2' => [
Shopware_Controllers_Frontend_PaypalUnifiedV2::class,
'indexAction',
true,
];

yield 'Shopware_Controllers_Widgets_PaypalUnifiedV2AdvancedCreditDebitCard' => [
Shopware_Controllers_Widgets_PaypalUnifiedV2AdvancedCreditDebitCard::class,
'createOrderAction',
true,
];

yield 'Shopware_Controllers_Widgets_PaypalUnifiedV2SmartPaymentButtons' => [
Shopware_Controllers_Widgets_PaypalUnifiedV2SmartPaymentButtons::class,
'createOrderAction',
true,
];

yield 'Shopware_Controllers_Frontend_PaypalUnifiedApm' => [
Shopware_Controllers_Frontend_PaypalUnifiedApm::class,
'indexAction',
false,
];

yield 'Shopware_Controllers_Frontend_PaypalUnifiedV2PayUponInvoice' => [
Shopware_Controllers_Frontend_PaypalUnifiedV2PayUponInvoice::class,
'indexAction',
false,
];
}
}
19 changes: 13 additions & 6 deletions Tests/Functional/Controller/Frontend/PaypalUnifiedV2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
use Enlight_Components_Session_Namespace as ShopwareSession;
use Enlight_Controller_Request_RequestTestCase;
use Enlight_Controller_Response_ResponseTestCase;
use Enlight_Controller_Router;
use Enlight_Template_Manager;
use Enlight_View_Default;
use Generator;
use PHPUnit\Framework\TestCase;
use Shopware\Components\BasketSignature\BasketPersister;
Expand Down Expand Up @@ -76,6 +79,7 @@ public function testIndexErrorHandling(
$dependencyProvider = $this->createConfiguredMock(DependencyProvider::class, [
'getSession' => $session,
'getModule' => new stdClass(),
'getRouter' => $this->createMock(Enlight_Controller_Router::class),
]);

$redirectDataBuilder = $this->createMock(RedirectDataBuilder::class);
Expand Down Expand Up @@ -131,9 +135,14 @@ public function testIndexErrorHandling(
$basketPersister = $this->createMock(BasketPersister::class);
}

$payPalOrderParameterMock = $this->createMock(PayPalOrderParameter::class);
if (\is_array($orderData)) {
$payPalOrderParameterMock->method('getCart')->willReturn(\is_array($orderData['sBasket']) ? $orderData['sBasket'] : []);
}

$cartPersister = $this->createMock(CartPersister::class);
$orderParameterFacade = $this->createConfiguredMock(PayPalOrderParameterFacadeInterface::class, [
'createPayPalOrderParameter' => $this->createMock(PayPalOrderParameter::class),
'createPayPalOrderParameter' => $payPalOrderParameterMock,
]);

$dispatchValidation = $this->createMock(DispatchValidation::class);
Expand Down Expand Up @@ -191,7 +200,7 @@ public function orderDataProvider()
yield 'Exception in OrderBuilder::getOrder should lead to ErrorCodes::UNKNOWN' => [
[
'sUserData' => [],
'sBasket' => [],
'sBasket' => ['content' => [0 => ['anyItem']]],
],
false,
false,
Expand All @@ -203,7 +212,7 @@ public function orderDataProvider()
yield 'Exception during order creation request should lead to ErrorCodes::COMMUNICATION_FAILURE' => [
[
'sUserData' => [],
'sBasket' => [],
'sBasket' => ['content' => [0 => ['anyItem']]],
],
false,
false,
Expand All @@ -213,9 +222,6 @@ public function orderDataProvider()
];
}

/**
* @param Container $container
*/
private function getController(Container $container = null)
{
$request = new Enlight_Controller_Request_RequestTestCase();
Expand All @@ -229,6 +235,7 @@ private function getController(Container $container = null)

$controller->setRequest($request);
$controller->setResponse($response);
$controller->setView(new Enlight_View_Default(new Enlight_Template_Manager()));

if ($container instanceof Container) {
$controller->setContainer($container);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public function testPatchAddressAction()
private function createOrderParameterFacade()
{
$facade = $this->createMock(PayPalOrderParameterFacadeInterface::class);
$payPalOrderParameter = new PayPalOrderParameter([], [], PaymentType::PAYPAL_EXPRESS_V2, null, null, 'anyOrderNumber');
$payPalOrderParameter = new PayPalOrderParameter([], ['content' => ['anyItem' => []]], PaymentType::PAYPAL_EXPRESS_V2, null, null, 'anyOrderNumber');
$facade->method('createPayPalOrderParameter')->willReturn($payPalOrderParameter);

return $facade;
Expand Down

0 comments on commit afc1e35

Please sign in to comment.