Skip to content

Commit

Permalink
NTR: PISHPS-332: Paypal Express headless support
Browse files Browse the repository at this point in the history
  • Loading branch information
Vitalij Mik committed Oct 25, 2024
1 parent bd7aa91 commit 92f0b39
Show file tree
Hide file tree
Showing 41 changed files with 3,163 additions and 2,033 deletions.
36 changes: 36 additions & 0 deletions polyfill/Shopware/Core/Framework/HttpException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types=1);

namespace Shopware\Core\Framework;

use Shopware\Core\Framework\Log\Package;

#[Package('core')]
abstract class HttpException extends ShopwareHttpException
{
protected static string $couldNotFindMessage = 'Could not find {{ entity }} with {{ field }} "{{ value }}"';

public function __construct(
protected int $statusCode,
protected string $errorCode,
string $message,
array $parameters = [],
?\Throwable $previous = null
) {
parent::__construct($message, $parameters, $previous);
}

public function getErrorCode(): string
{
return $this->errorCode;
}

public function getStatusCode(): int
{
return $this->statusCode;
}

public function is(string ...$code): bool
{
return \in_array($this->errorCode, $code, true);
}
}
104 changes: 104 additions & 0 deletions src/Components/PaypalExpress/PaypalExpressException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Components\PaypalExpress;

use Shopware\Core\Framework\HttpException;
use Symfony\Component\HttpFoundation\Response;

class PaypalExpressException extends HttpException
{
public const PAYMENT_METHOD_DISABLED = 'PAYMENT_METHOD_DISABLED';
public const EMPTY_CART = 'EMPTY_CART';

public const MISSING_SESSION_ID = 'MISSING_SESSION_ID';

public const MISSING_CART_SESSION_ID = 'MISSING_CART_SESSION_ID';
public const MISSING_SHIPPING_ADDRESS = 'MISSING_SHIPPING_ADDRESS';
public const MISSING_BILLING_ADDRESS = 'MISSING_BILLING_ADDRESS';

public const BILLING_ADDRESS_PARSING_ERROR = 'BILLING_ADDRESS_PARSING_ERROR';
public const SHIPPING_ADDRESS_PARSING_ERROR = 'SHIPPING_ADDRESS_PARSING_ERROR';

public static function paymentNotEnabled(string $salesChannelId): PaypalExpressException
{
return new self(
Response::HTTP_BAD_REQUEST,
self::PAYMENT_METHOD_DISABLED,
'Paypal Express is not enabled for SalesChannelId: {{salesChannelId}}',
[
'salesChannelId' => $salesChannelId
]
);
}

public static function cartIsEmpty(): PaypalExpressException
{
return new self(
Response::HTTP_BAD_REQUEST,
self::EMPTY_CART,
'Current Cart is empty'
);
}

public static function missingSessionId(): PaypalExpressException
{
return new self(
Response::HTTP_BAD_REQUEST,
self::MISSING_SESSION_ID,
'Session ID is missing, please check error logs'
);
}

public static function cartSessionIdIsEmpty(): PaypalExpressException
{
return new self(
Response::HTTP_BAD_REQUEST,
self::MISSING_CART_SESSION_ID,
'Session ID is missing in cart extensions'
);
}

public static function shippingAddressMissing(): PaypalExpressException
{
return new self(
Response::HTTP_BAD_REQUEST,
self::MISSING_SHIPPING_ADDRESS,
'Shipping Address is missing'
);
}

public static function billingAddressMissing(): PaypalExpressException
{
return new self(
Response::HTTP_BAD_REQUEST,
self::MISSING_BILLING_ADDRESS,
'Billing Address is missing'
);
}

public static function billingAddressError(string $message, \stdClass $billingAddress): PaypalExpressException
{
return new self(
Response::HTTP_BAD_REQUEST,
self::BILLING_ADDRESS_PARSING_ERROR,
'Failed to parse billing address with following error {{error}}',
[
'error' => $message,
'billingAddress' => (array)$billingAddress
]
);
}
public static function shippingAddressError(string $message, \stdClass $shippingAddress): PaypalExpressException
{
return new self(
Response::HTTP_BAD_REQUEST,
self::SHIPPING_ADDRESS_PARSING_ERROR,
'Failed to parse shipping address with following error {{error}}',
[
'error' => $message,
'shippingAddress' => (array)$shippingAddress
]
);
}
}
12 changes: 12 additions & 0 deletions src/Components/PaypalExpress/Route/AbstractCancelCheckoutRoute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Components\PaypalExpress\Route;

use Shopware\Core\System\SalesChannel\SalesChannelContext;

abstract class AbstractCancelCheckoutRoute
{
abstract public function getDecorated(): AbstractStartCheckoutRoute;
abstract public function cancelCheckout(SalesChannelContext $context): CancelCheckoutResponse;
}
12 changes: 12 additions & 0 deletions src/Components/PaypalExpress/Route/AbstractFinishCheckoutRoute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Components\PaypalExpress\Route;

use Shopware\Core\System\SalesChannel\SalesChannelContext;

abstract class AbstractFinishCheckoutRoute
{
abstract public function getDecorated(): AbstractStartCheckoutRoute;
abstract public function finishCheckout(SalesChannelContext $context): FinishCheckoutResponse;
}
13 changes: 13 additions & 0 deletions src/Components/PaypalExpress/Route/AbstractStartCheckoutRoute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Components\PaypalExpress\Route;

use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\Request;

abstract class AbstractStartCheckoutRoute
{
abstract public function getDecorated(): AbstractStartCheckoutRoute;
abstract public function startCheckout(Request $request, SalesChannelContext $context): StartCheckoutResponse;
}
33 changes: 33 additions & 0 deletions src/Components/PaypalExpress/Route/CancelCheckoutResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Components\PaypalExpress\Route;

use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\System\SalesChannel\StoreApiResponse;

/**
* @final
*/
class CancelCheckoutResponse extends StoreApiResponse
{
private string $sessionId;


public function __construct(string $sessionId)
{
$this->sessionId = $sessionId;

parent::__construct(new ArrayStruct(
[
'sessionId' => $sessionId,
],
'paypal_express_cancel_checkout_response'
));
}

public function getSessionId(): string
{
return $this->sessionId;
}
}
75 changes: 75 additions & 0 deletions src/Components/PaypalExpress/Route/CancelCheckoutRoute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Components\PaypalExpress\Route;

use Kiener\MolliePayments\Components\PaypalExpress\PayPalExpress;
use Kiener\MolliePayments\Components\PaypalExpress\PaypalExpressException;
use Kiener\MolliePayments\Service\Cart\CartBackupService;
use Kiener\MolliePayments\Service\CartServiceInterface;
use Kiener\MolliePayments\Service\CustomFieldsInterface;
use Kiener\MolliePayments\Service\SettingsService;
use Shopware\Core\Framework\Plugin\Exception\DecorationPatternException;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\System\SalesChannel\SalesChannelContext;

/**
* @final
*/
class CancelCheckoutRoute extends AbstractCancelCheckoutRoute
{
private SettingsService $settingsService;
private CartBackupService $cartBackupService;
private PayPalExpress $paypalExpress;
private CartServiceInterface $cartService;

public function __construct(
SettingsService $settingsService,
CartBackupService $cartBackupService,
CartServiceInterface $cartService,
PayPalExpress $paypalExpress
) {
$this->settingsService = $settingsService;
$this->cartBackupService = $cartBackupService;
$this->paypalExpress = $paypalExpress;
$this->cartService = $cartService;
}

public function getDecorated(): AbstractStartCheckoutRoute
{
throw new DecorationPatternException(self::class);
}

public function cancelCheckout(SalesChannelContext $context): CancelCheckoutResponse
{
$settings = $this->settingsService->getSettings($context->getSalesChannelId());

if ($settings->isPaypalExpressEnabled() === false) {
throw PaypalExpressException::paymentNotEnabled($context->getSalesChannelId());
}


$cart = $this->cartService->getCalculatedMainCart($context);

$this->cartBackupService->restoreCart($context);
$this->cartBackupService->clearBackup($context);

$cartExtension = $cart->getExtension(CustomFieldsInterface::MOLLIE_KEY);
$sessionId = null;

if ($cartExtension instanceof ArrayStruct) {
$sessionId = $cartExtension[CustomFieldsInterface::PAYPAL_EXPRESS_SESSION_ID_KEY] ?? null;
}

if ($sessionId === null) {
throw PaypalExpressException::cartSessionIdIsEmpty();
}

try {
$session = $this->paypalExpress->cancelSession($sessionId, $context);
} catch (\Throwable $e) {
//todo: remove try catch once cancel is possible from mollie
}
return new CancelCheckoutResponse($sessionId);
}
}
39 changes: 39 additions & 0 deletions src/Components/PaypalExpress/Route/FinishCheckoutResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Components\PaypalExpress\Route;

use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\System\SalesChannel\StoreApiResponse;

/**
* @final
*/
class FinishCheckoutResponse extends StoreApiResponse
{
private string $sessionId;
private string $authenticateId;

public function __construct(string $sessionId, string $authenticateId)
{
$this->sessionId = $sessionId;
$this->authenticateId = $authenticateId;
parent::__construct(new ArrayStruct(
[
'sessionId' => $sessionId,
'authenticateId' => $authenticateId,
],
'paypal_express_finish_checkout_response'
));
}

public function getSessionId(): string
{
return $this->sessionId;
}

public function getAuthenticateId(): string
{
return $this->authenticateId;
}
}
Loading

0 comments on commit 92f0b39

Please sign in to comment.