Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(PT-13134): Prevent call create order with an empty cart #37

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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->offsetSet('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
13 changes: 13 additions & 0 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
<author>shopware AG</author>
<compatibility minVersion="5.2.27" maxVersion="5.99.99"/>

<changelog version="6.1.2">
<changes lang="de">
PT-13134 - Verhindert das Erstellen einer PayPal Zahlung mit einem leeren Warenkorb;
PT-13138 - Verbessert die Bearbeitung von Webhooks;
PT-13140 - Die Zahlungsart "MyBank" ist nun standardmäßig deaktiviert;
</changes>
<changes lang="en">
PT-13134 - Prevents the creation of a PayPal payment with an empty shopping cart;
PT-13138 - Improves the processing of webhooks;
PT-13140 - The payment method "MyBank" is now deactivated by default;
</changes>
</changelog>

<changelog version="6.1.1">
<changes lang="de">
PT-13127 - Verbessert die Benutzerfreundlichkeit für den Rechnungskauf im Checkout-Formular;
Expand Down