From 15282ff8b35aa60e8082a74621bf85191db3ee27 Mon Sep 17 00:00:00 2001 From: bortefi <44976351+bortefi@users.noreply.github.com> Date: Thu, 5 May 2022 11:20:40 +0200 Subject: [PATCH] Release 3.8.0 (#213) * ASW-393 fix grumphp blacklist dd regex * ASW-0 update grump config * ASW-0 3.2.0 changelog * ASW-0 update composer * ASW-429 add guzzlehttp * ASW-429 WIP add http client apple pay * ASW-429: WIP add zip extractor and fallback logic * ASW-429 add apple pay certificate decoder unit test * ASW-429 add apple pay certificate encoder unit test * ASW-429 add http code to log level unit test * ASW-429 add response status to log level unit test * ASW-429 add body logging middleware unit test * ASW-429 add header logging middleware unit test * ASW-429 add apple pay unit test * ASW-429 add apple pay handler unit test * ASW-429 add apple pay request unit test * ASW-429 add apple pay response unit test * ASW-429 add certificate writer unit test * ASW-429 WIP add zip extractor unit test * ASW-429 add stream transport factory unit test * ASW-429 remove to/file * ASW-429 add assertions on file removal on CertificateWriterTest * ASW-429 fix ZipExtractorTest * ASW-429 refactor apple pay certificate code review * ASW-429 remove suppress from HeaderLoggingMiddleware * ASW-429 rename service xml * ASW-429 remove body from logging * ASW-429 make PlainTextEncoder final * ASW-429 add original exception to CouldNotWriteCertificate * ASW-429 make CertificateWriter more specific, update tests * ASW-429 refactor ZipExtractorTest * ASW-429 re-add CertificateWriterTest * ASW-429 keep exception history * ASW-429 refactor logging infi * ASW-429 rename ApplePay model to ApplePayCertificate * ASW-429 add parameter base_uri * ASW-429 rename ApplePayRequest to ApplePayCertificateRequest, change tests * ASW-429 refactor handler, decoder and make the shit work * ASW-429 remove comment * ASW-429 rename ApplePayTestCertificate to postfix Test * ASW-429: refactor the shit out of it * ASW-429 change const usage * ASW-429 remove unused dependency * ASW-429 inject stream transport as a factory * ASW-430 WIP add apple pay certificate url rewriter * ASW-430 WIP working url rewrite for cronjob * ASW-430 make certificate available on endpoint * ASW-430 make apple pay certificate available on endpoint using cronjob and live * ASW-430 WIP add ApplePayTransportHandler on install * ASW-430: WIP add import button and functionality * ASW-429 ASW-430 rework Adyen ApplePay Merchant id assocation * ASW-429-430 cleanup config * ASW-429-430 remove obsolete config * ASW-429-430 keep zip fixture * ASW-429 ASW-430 fix type condition * ASW-429 ASW-430 fix type condition, with error code * ASW-429 ASW-430 update composer lock * ASW-0 bump version 3.3.0, add plugin notes * ASW-401: fix adyen plugin compatible with SWAGPayPalUnified * ASW-401 add escapeWithQuotes to Sanitize * ASW-401 add unit test SanitizeTest * ASW-401 add escapeWithQuotes testcase to SwPaymentMeanSerializerTest * ASW-401 remove Object.values on ApplePayMethod and getPaymentMethodId * ASW-401 remove object values on setConfig adyen enriched payment methods * ASW-401 WIP refactor sAdyenConfig using endpoint instead of data attribute * ASW-401 remove data- attribute for sAdyenConfig * ASW-401 refactor urls * ASW-432 handle apple pay component request * ASW-432 make currency dynamic * ASW-432 WIP make adyenOrderTotal available over config api endpoint * ASW-432 fix adyenOrderTotal and currency to be fetched using ajax via config * ASW-432 refactor handle to buildComponentApplePay * ASW-432 refactor ApplePay build component data to checkout component data * ASW-432 remove session from buildcomponentdata and move it to handleComponent * ASW-432 add comment check early return is possible in future * ASW-432 remove todo comment after testing it * ASW-0 update php-cs-fixer-config * ASW-0 update release notes * ASW-0 update pipline for master branch * ASW-436 fix nullable data from attribute, add enriched test * ASW-436 handle exceptions * ASW-436 clear config cache on backen api action * ASW-376 - Stored payment methods * ASW-376 - Unit test * ASW-375 - Stored payment umbrella installation * ASW-375 - Query * ASW-375 - Hide from admin * ASW-375 - Unit tests * ASW-375 - CR fixes * ASW-375 - Hide field check * ASW-375 - Hide on backend shipping section * ASW-375 - Secure susbscribers * ASW-375 - ASW-379 - Hide refactor * ASW-375 - CR fixes * ASW-375 - CR fixes * ASW-375 refactor code * ASW-375 rename test case * ASW-375 cs flavour * ASW-375 cleanup code, fix test: use real implementation over mocks * ASW-376 - Unit tests * ASW-376 - CR fixes * ASW-378 - Disabled stored methods pick * ASW-378 - Template fix * ASW-377 - EnrichedPaymentMeanProvider for stored methods * ASW-377 - Stored methods selection * ASW-377 - Payment mean selection * ASW-377 - Subscribers and session handler * ASW-377 - CR fixes * ASW-377 - Stored Method ID save and CR fixes * ASW-377 - PaymentMeanCollection tests * ASW-377 - EnrichedPaymentMeanProviderTest updated * ASW-377 - PaymentMethodEnricher unit test * ASW-377 - Admin get payments refactor and unit tests * ASW-377 - Fixed issue and unit tests * ASW-377 - PersistStoredMethodIdSubscriber unit tests * ASW-377 - Fixed config * ASW-435 - Attribute removed * ASW-377 - CR fixes * ASW-377 - CR fixes * ASW-377 fix add subshops on install/update * ASW-461 - My account preselected stored methods * ASW-461 - Preselected stored methods in checkout * ASW-461 - Fixed unit tests * ASW-461 - New unit test * ASW-461 - Account subscriber unit test * ASW-461 - Account subscriber unit test fix * ASW-461 - Renamed test * ASW-461 - Test clarification * ASW-461 - Unused class * ASW-461 - User preference unit test * ASW-461 - CR fixes * ASW-461 - CR fixes * ASW-461 - CR fixes * ASW-461 - CR fix * ASW-461 - Single fetch fix * ASW-466 - Guests fix * ASW-466 - Fix type * ASW-466 - Test name fix * ASW-466 - CR fix * ASW-0 Bump version 3.3.1 * ASW-0 Bump version 3.4.0, changelog * Release 3.4.0 (#203) * ASW-0 update pipline for master branch * ASW-436 fix nullable data from attribute, add enriched test * ASW-436 handle exceptions * ASW-436 clear config cache on backen api action * ASW-376 - Stored payment methods * ASW-376 - Unit test * ASW-375 - Stored payment umbrella installation * ASW-375 - Query * ASW-375 - Hide from admin * ASW-375 - Unit tests * ASW-375 - CR fixes * ASW-375 - Hide field check * ASW-375 - Hide on backend shipping section * ASW-375 - Secure susbscribers * ASW-375 - ASW-379 - Hide refactor * ASW-375 - CR fixes * ASW-375 - CR fixes * ASW-375 refactor code * ASW-375 rename test case * ASW-375 cs flavour * ASW-375 cleanup code, fix test: use real implementation over mocks * ASW-376 - Unit tests * ASW-376 - CR fixes * ASW-378 - Disabled stored methods pick * ASW-378 - Template fix * ASW-377 - EnrichedPaymentMeanProvider for stored methods * ASW-377 - Stored methods selection * ASW-377 - Payment mean selection * ASW-377 - Subscribers and session handler * ASW-377 - CR fixes * ASW-377 - Stored Method ID save and CR fixes * ASW-377 - PaymentMeanCollection tests * ASW-377 - EnrichedPaymentMeanProviderTest updated * ASW-377 - PaymentMethodEnricher unit test * ASW-377 - Admin get payments refactor and unit tests * ASW-377 - Fixed issue and unit tests * ASW-377 - PersistStoredMethodIdSubscriber unit tests * ASW-377 - Fixed config * ASW-435 - Attribute removed * ASW-377 - CR fixes * ASW-377 - CR fixes * ASW-377 fix add subshops on install/update * ASW-461 - My account preselected stored methods * ASW-461 - Preselected stored methods in checkout * ASW-461 - Fixed unit tests * ASW-461 - New unit test * ASW-461 - Account subscriber unit test * ASW-461 - Account subscriber unit test fix * ASW-461 - Renamed test * ASW-461 - Test clarification * ASW-461 - Unused class * ASW-461 - User preference unit test * ASW-461 - CR fixes * ASW-461 - CR fixes * ASW-461 - CR fixes * ASW-461 - CR fix * ASW-461 - Single fetch fix * ASW-466 - Guests fix * ASW-466 - Fix type * ASW-466 - Test name fix * ASW-466 - CR fix * ASW-0 Bump version 3.3.1 * ASW-0 Bump version 3.4.0, changelog Co-authored-by: Damian Pastorini Co-authored-by: davebueds * ASW-0 bump version 3.5.0 * ASW-476 refactor result codes, add result code handler, add tests, refactor * ASW-472 add model ShopperInteraction and test * ASW-476 add missing unit test cases * ASW-473 add model RecurringProcessingModel and test * ASW-477 add CustomerNumberProvider, test and refactor PaymentMethodService * ASW-470 add RecurringPaymentToken model and unit test * ASW-472 Add shopperinteractions, fix tests * ASW-473 fix cr feedback * ASW-473 fix cr feedback * ASW-477 apply fixes CR * ASW-470 make orderNumber not nullable, add tests, add indexes * ASW-476 add invalid status + test * ASW-469 Add mapper RecurringTokenMapper and unit test * ASW-469 add invalidPaymentsResponseException + test * ASW-469 refactor test * ASW-476 remove PaymentResultCodeHandler and test, leave it in Adyen.php * ASW-476 add extra test cases * ASW-470 refactor so it uses uuid tokens * ASW-470 id strategy none * ASW-471 WIP add RecurringPaymentTokenRepository * ASW-471 add config and traceable recurring payment token repository * ASW-473 - CR fixes * ASW-473 - CR fix * ASW-476 - CR fixes * ASW-476 - CR fixes * ASW-469 - CR fixes * ASW-471 - CR fixes and unit tests * ASW-471 - CR fixes and tests * ASW-471 - CR fixes * ASW-477 - CR comment * ASW-470 - CR fixes * ASW-470 - CR fixes * ASW-474 - Recurring one off payment token provider * ASW-474 - Validation changes * ASW-474 - Changes and unit tests * ASW-476 - CR fixes * ASW-479 Recurring-disable * ASW-479 update cs * ASW-471 - CR fixes * ASW-469 - CR fixes * ASW-472 - CR fixes * ASW-479 Recurring-disable * ASW-479 update cs * ASW-499 - Disable token request handler * ASW-499 - Disable token request handler interface * ASW-499 - Refactor and unit tests * ASW-499 - Unit tests * ASW-499 - DisableTokenRequestHandler unit tests * ASW-499 - Fix * ASW-499 - Handler changes * ASW-499 - FrontendJsonResponse test * ASW-499 - Integration test file * ASW-499 - CR fixes * ASW-499 - Logger assert * ASW-499 - Validate message * ASW-499 - CR change * ASW-500 - Frontend controller for disable token * ASW-500 - Result changed * ASW-500 - Method name * ASW-500 - Controller name * ASW-500 - Controller folder * ASW-500 - Config fixes * ASW-500 - Unit test note * ASW-500 - CR fix * ASW-500 - Refactor after rebase * ASW-500 - CR fixes * ASW-500 - CR fixes * ASW-500 - CR fixes * ASW-501 - Disable payment button * ASW-501 - ASW-500 related changes * ASW-501 - CR changes * ASW-501 - API URL * ASW-501 fix data attributes (url broken) * ASW-0 update changelog * ASW-496 guest account has an empty basket * ASW-496 use checkout basket endpoint instead of session basket * ASW-496 wip add checkout getbasket unit test * ASW-496 apple pay was still using old values, because component wasnt rebuild * ASW-486 remove sanitize escape no quotes * ASW-486 remove santizing on name and description as well * ASW-0 update changelog release 3.7.0 * ASW-502 - Confirmation modal * ASW-502 - Styles fix * ASW-502 - Confirmation modal * ASW-502 rework null check * ASW-335 add duplicate notifications check * ASW-335 duplicate notification exception in const * ASW-335 remove isDuplicate method * ASW-335 add duplicated notification handling on text notifications as well * ASW-335 rework CR * ASW-335 rework so it uses specification pattern on guardDuplicate notification * ASW-437 add checkout basket provider which uses checkout controller get basket * ASW-535 additional description * ASW-535 use snippets as fallback when no additional description is set * ASW-493 - Config URL param * ASW-445 Version 3.8.0 & changelog Co-authored-by: davebueds Co-authored-by: Damian Pastorini --- Components/Adyen/PaymentMethodService.php | 1 - Components/Builder/NotificationBuilder.php | 1 + Components/IncomingNotificationManager.php | 32 ++-- Components/NotificationManager.php | 19 +++ Components/NotificationProcessor.php | 30 ++-- Controllers/Frontend/AdyenConfig.php | 11 +- .../Frontend/DisableRecurringToken.php | 21 ++- Enricher/Payment/PaymentMethodEnricher.php | 18 +- Exceptions/DuplicateNotificationException.php | 28 ++++ .../js/jquery.adyen-disable-payment.js | 50 +++++- .../js/jquery.adyen-payment-selection.js | 50 +++--- Resources/frontend/less/all.less | 19 +++ Resources/services/components.xml | 1 + Resources/services/managers.xml | 1 + Resources/services/shopware.xml | 4 + Resources/services/subscribers.xml | 1 + Resources/services/validators.xml | 2 +- .../frontend/checkout/adyen_configuration.tpl | 1 + .../frontend/register/payment_fieldset.tpl | 18 ++ Shopware/Provider/CheckoutBasketProvider.php | 26 +++ .../CheckoutBasketProviderInterface.php | 10 ++ .../Serializer/SwPaymentMeanSerializer.php | 7 +- Subscriber/CheckoutSubscriber.php | 9 +- Utils/Sanitize.php | 5 - plugin.xml | 26 ++- .../Payment/PaymentMethodEnricherTest.php | 9 +- .../DuplicateNotificationExceptionTest.php | 49 ++++++ .../Controllers/Frontend/CheckoutTest.php | 155 ++++++++++++++++++ .../SwPaymentMeanSerializerTest.php | 6 +- tests/Unit/Utils/SanitizeTest.php | 8 - 30 files changed, 516 insertions(+), 102 deletions(-) create mode 100644 Exceptions/DuplicateNotificationException.php create mode 100644 Shopware/Provider/CheckoutBasketProvider.php create mode 100644 Shopware/Provider/CheckoutBasketProviderInterface.php create mode 100644 tests/Unit/Exceptions/DuplicateNotificationExceptionTest.php create mode 100644 tests/Unit/Shopware/Controllers/Frontend/CheckoutTest.php diff --git a/Components/Adyen/PaymentMethodService.php b/Components/Adyen/PaymentMethodService.php index 11fd55de..f9d590b1 100644 --- a/Components/Adyen/PaymentMethodService.php +++ b/Components/Adyen/PaymentMethodService.php @@ -14,7 +14,6 @@ use AdyenPayment\Session\CustomerNumberProviderInterface; use Psr\Log\LoggerInterface; - /** @TODO - Cleanup the public const (unify the services) and create unit tests */ final class PaymentMethodService implements PaymentMethodServiceInterface { diff --git a/Components/Builder/NotificationBuilder.php b/Components/Builder/NotificationBuilder.php index 978d717e..b47ef3bb 100644 --- a/Components/Builder/NotificationBuilder.php +++ b/Components/Builder/NotificationBuilder.php @@ -68,6 +68,7 @@ public function fromParams($params): Notification } $notification->setOrder($order); + $notification->setOrderId($order->getId()); if (isset($params['pspReference'])) { $notification->setPspReference($params['pspReference']); diff --git a/Components/IncomingNotificationManager.php b/Components/IncomingNotificationManager.php index b1ad831a..e098955a 100644 --- a/Components/IncomingNotificationManager.php +++ b/Components/IncomingNotificationManager.php @@ -5,6 +5,7 @@ namespace AdyenPayment\Components; use AdyenPayment\Components\Builder\NotificationBuilder; +use AdyenPayment\Exceptions\DuplicateNotificationException; use AdyenPayment\Exceptions\InvalidParameterException; use AdyenPayment\Exceptions\OrderNotFoundException; use AdyenPayment\Models\Feedback\TextNotificationItemFeedback; @@ -18,20 +19,10 @@ */ class IncomingNotificationManager { - /** - * @var LoggerInterface - */ - private $logger; - - /** - * @var NotificationBuilder - */ - private $notificationBuilder; - - /** - * @var ModelManager - */ - private $entityManager; + private LoggerInterface $logger; + private NotificationBuilder $notificationBuilder; + private ModelManager $entityManager; + private NotificationManager $notificationManager; /** * IncomingNotificationManager constructor. @@ -39,11 +30,13 @@ class IncomingNotificationManager public function __construct( LoggerInterface $logger, NotificationBuilder $notificationBuilder, - ModelManager $entityManager + ModelManager $entityManager, + NotificationManager $notificationManager ) { $this->logger = $logger; $this->notificationBuilder = $notificationBuilder; $this->entityManager = $entityManager; + $this->notificationManager = $notificationManager; } /** @@ -60,6 +53,9 @@ public function convertNotifications(array $textNotifications): void $notification = $this->notificationBuilder->fromParams( json_decode($textNotificationItem->getTextNotification(), true) ); + + $this->notificationManager->guardDuplicate($notification); + $this->entityManager->persist($notification); } } catch (InvalidParameterException $exception) { @@ -70,10 +66,14 @@ public function convertNotifications(array $textNotifications): void $this->logger->warning( $exception->getMessage().' '.$textNotificationItem->getTextNotification() ); + } catch (DuplicateNotificationException $exception) { + $this->logger->notice( + $exception->getMessage() + ); } $this->entityManager->remove($textNotificationItem); + $this->entityManager->flush(); } - $this->entityManager->flush(); } /** diff --git a/Components/NotificationManager.php b/Components/NotificationManager.php index fa012c17..b4ecf8f9 100644 --- a/Components/NotificationManager.php +++ b/Components/NotificationManager.php @@ -4,6 +4,7 @@ namespace AdyenPayment\Components; +use AdyenPayment\Exceptions\DuplicateNotificationException; use AdyenPayment\Models\Enum\NotificationStatus; use AdyenPayment\Models\Notification; use Doctrine\ORM\EntityRepository; @@ -98,4 +99,22 @@ public function getLastNotificationForPspReference(string $pspReference) return; } } + + public function guardDuplicate(Notification $notification): void + { + $record = $this->notificationRepository->findOneBy([ + 'orderId' => $notification->getOrderId(), + 'pspReference' => $notification->getPspReference(), + 'paymentMethod' => $notification->getPaymentMethod(), + 'success' => $notification->isSuccess(), + 'eventCode' => $notification->getEventCode(), + 'merchantAccountCode' => $notification->getMerchantAccountCode(), + 'amountValue' => $notification->getAmountValue(), + 'amountCurrency' => $notification->getAmountCurrency(), + ]); + + if ($record instanceof Notification) { + throw DuplicateNotificationException::withNotification($record); + } + } } diff --git a/Components/NotificationProcessor.php b/Components/NotificationProcessor.php index fc4274f1..7268efd9 100644 --- a/Components/NotificationProcessor.php +++ b/Components/NotificationProcessor.php @@ -5,6 +5,7 @@ namespace AdyenPayment\Components; use AdyenPayment\Components\NotificationProcessor\NotificationProcessorInterface; +use AdyenPayment\Exceptions\DuplicateNotificationException; use AdyenPayment\Exceptions\NoNotificationProcessorFoundException; use AdyenPayment\Exceptions\OrderNotFoundException; use AdyenPayment\Models\Enum\NotificationStatus; @@ -26,21 +27,10 @@ class NotificationProcessor * @var NotificationProcessorInterface[] */ private $processors; - - /** - * @var LoggerInterface - */ - private $logger; - - /** - * @var ModelManager - */ - private $modelManager; - - /** - * @var ContainerAwareEventManager - */ - private $eventManager; + private LoggerInterface $logger; + private ModelManager $modelManager; + private ContainerAwareEventManager $eventManager; + private NotificationManager $notificationManager; /** * NotificationProcessor constructor. @@ -50,11 +40,13 @@ class NotificationProcessor public function __construct( LoggerInterface $logger, ModelManager $modelManager, - ContainerAwareEventManager $eventManager + ContainerAwareEventManager $eventManager, + NotificationManager $notificationManager ) { $this->logger = $logger; $this->modelManager = $modelManager; $this->eventManager = $eventManager; + $this->notificationManager = $notificationManager; } /** @@ -68,6 +60,10 @@ public function processMany(Traversable $notifications): \Generator foreach ($notifications as $notification) { try { yield from $this->process($notification); + } catch (DuplicateNotificationException $exception) { + $this->logger->notice( + $exception->getMessage() + ); } catch (NoNotificationProcessorFoundException $exception) { $this->logger->notice( 'No notification processor found', @@ -105,6 +101,8 @@ public function processMany(Traversable $notifications): \Generator */ private function process(Notification $notification): \Generator { + $this->notificationManager->guardDuplicate($notification); + $processors = $this->findProcessors($notification); if (empty($processors)) { diff --git a/Controllers/Frontend/AdyenConfig.php b/Controllers/Frontend/AdyenConfig.php index 72869df9..aae1196d 100644 --- a/Controllers/Frontend/AdyenConfig.php +++ b/Controllers/Frontend/AdyenConfig.php @@ -11,14 +11,13 @@ use AdyenPayment\Serializer\PaymentMeanCollectionSerializer; use AdyenPayment\Shopware\Serializer\SwPaymentMeanCollectionSerializer; -class Shopware_Controllers_Frontend_AdyenConfig extends Enlight_Controller_Action +class Shopware_Controllers_Frontend_AdyenConfig extends Shopware_Controllers_Frontend_Checkout { private DataConversion $dataConversion; private Configuration $configuration; private EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider; private PaymentMeanCollectionSerializer $paymentMeanCollectionSerializer; private Shopware_Components_Modules $modules; - private Enlight_Components_Session_Namespace $session; public function preDispatch(): void { @@ -27,7 +26,6 @@ public function preDispatch(): void $this->enrichedPaymentMeanProvider = $this->get(EnrichedPaymentMeanProvider::class); $this->paymentMeanCollectionSerializer = $this->get(SwPaymentMeanCollectionSerializer::class); $this->modules = $this->get('modules'); - $this->session = Shopware()->Session(); } public function indexAction(): void @@ -42,9 +40,10 @@ public function indexAction(): void PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()) ); - $sBasket = $this->session->sOrderVariables['sBasket']; + $sBasket = $this->getBasket(); $shop = Shopware()->Shop(); + $orderCurrency = $shop->getCurrency(); $adyenConfig = [ 'status' => 'success', @@ -52,8 +51,8 @@ public function indexAction(): void 'clientKey' => $this->configuration->getClientKey($shop), 'environment' => $this->configuration->getEnvironment($shop), 'enrichedPaymentMethods' => ($this->paymentMeanCollectionSerializer)($enrichedPaymentMethods), - 'adyenOrderTotal' => $sBasket['sAmount'], - 'adyenOrderCurrency' => $sBasket['sCurrencyName'] + 'adyenOrderTotal' => round($sBasket['sAmount'], 2), + 'adyenOrderCurrency' => $sBasket['sCurrencyName'] ?? $orderCurrency ]; $this->Response()->setBody( diff --git a/Controllers/Frontend/DisableRecurringToken.php b/Controllers/Frontend/DisableRecurringToken.php index 9ff33d1c..370f89fb 100644 --- a/Controllers/Frontend/DisableRecurringToken.php +++ b/Controllers/Frontend/DisableRecurringToken.php @@ -15,11 +15,13 @@ class Shopware_Controllers_Frontend_DisableRecurringToken extends Enlight_Contro { private ApiJsonResponse $frontendJsonResponse; private DisableTokenRequestHandlerInterface $disableTokenRequestHandler; + private Shopware_Components_Snippet_Manager $snippets; public function preDispatch(): void { $this->frontendJsonResponse = $this->get(FrontendJsonResponse::class); $this->disableTokenRequestHandler = $this->get(DisableTokenRequestHandler::class); + $this->snippets = $this->get('snippets'); } public function disabledAction(): void @@ -29,7 +31,11 @@ public function disabledAction(): void $this->frontendJsonResponse->sendJsonBadRequestResponse( $this->Front(), $this->Response(), - 'Invalid method.' + $this->snippets->getNamespace('adyen/checkout/error')->get( + 'disableTokenInvalidMethodMessage', + 'Invalid method.', + true + ) ); return; @@ -40,7 +46,11 @@ public function disabledAction(): void $this->frontendJsonResponse->sendJsonBadRequestResponse( $this->Front(), $this->Response(), - 'Missing recurring token param.' + $this->snippets->getNamespace('adyen/checkout/error')->get( + 'disableTokenMissingRecurringTokenMessage', + 'Missing recurring token param.', + true + ) ); return; @@ -48,12 +58,11 @@ public function disabledAction(): void $result = $this->disableTokenRequestHandler->disableToken($recurringToken, Shopware()->Shop()); if (!$result->isSuccess()) { - $this->frontendJsonResponse->sendJsonResponse( + $this->frontendJsonResponse->sendJsonBadRequestResponse( $this->Front(), $this->Response(), - JsonResponse::create( - ['error' => true, 'message' => $result->message()], - Response::HTTP_BAD_REQUEST + $this->snippets->getNamespace('adyen/checkout/error')->get( + $result->message() ) ); diff --git a/Enricher/Payment/PaymentMethodEnricher.php b/Enricher/Payment/PaymentMethodEnricher.php index 21b67139..dc2b2388 100644 --- a/Enricher/Payment/PaymentMethodEnricher.php +++ b/Enricher/Payment/PaymentMethodEnricher.php @@ -26,7 +26,7 @@ public function __invoke(array $shopwareMethod, PaymentMethod $paymentMethod): a { return array_merge($shopwareMethod, [ 'enriched' => true, - 'additionaldescription' => $this->enrichAdditionalDescription($paymentMethod), + 'additionaldescription' => $this->enrichAdditionalDescription($shopwareMethod, $paymentMethod), 'image' => $this->imageLogoProvider->provideByType($paymentMethod->adyenType()->type()), 'isStoredPayment' => $paymentMethod->isStoredPayment(), 'isAdyenPaymentMethod' => true, @@ -37,19 +37,23 @@ public function __invoke(array $shopwareMethod, PaymentMethod $paymentMethod): a ); } - private function enrichAdditionalDescription(PaymentMethod $adyenMethod): string + private function enrichAdditionalDescription(array $shopwareMethod, PaymentMethod $adyenMethod): string { - $description = $this->snippets - ->getNamespace('adyen/method/description') - ->get($adyenMethod->adyenType()->type()) ?? ''; + $additionalDescription = $shopwareMethod['additionaldescription'] ?? ''; + + if ('' === $additionalDescription) { + $additionalDescription = $this->snippets + ->getNamespace('adyen/method/description') + ->get($shopwareMethod['attribute']['adyen_type'] ?? '') ?? ''; + } if (!$adyenMethod->isStoredPayment()) { - return $description; + return $additionalDescription; } return sprintf( '%s%s: %s', - ($description ? $description.' ' : ''), + ($additionalDescription ? $additionalDescription.' ' : ''), $this->snippets ->getNamespace('adyen/checkout/payment') ->get('CardNumberEndingOn', 'Card number ending on', true), diff --git a/Exceptions/DuplicateNotificationException.php b/Exceptions/DuplicateNotificationException.php new file mode 100644 index 00000000..8edf5474 --- /dev/null +++ b/Exceptions/DuplicateNotificationException.php @@ -0,0 +1,28 @@ +getId(), + $notification->getOrderId(), + $notification->getPspReference(), + $notification->getStatus(), + $notification->getPaymentMethod(), + $notification->getEventCode(), + $notification->isSuccess(), + $notification->getMerchantAccountCode(), + $notification->getAmountValue(), + $notification->getAmountCurrency() + )); + } +} diff --git a/Resources/frontend/js/jquery.adyen-disable-payment.js b/Resources/frontend/js/jquery.adyen-disable-payment.js index 8bdf54a8..144474b4 100644 --- a/Resources/frontend/js/jquery.adyen-disable-payment.js +++ b/Resources/frontend/js/jquery.adyen-disable-payment.js @@ -23,15 +23,36 @@ * CSS classes selector to clear the error elements */ errorClassSelector: '.alert.is--error.is--rounded.is--adyen-error', + /** + * @var string modalSelector + * CSS classes selector to use as confirmation modal content. + */ + modalSelector: '.adyenDisableTokenConfirmationModal', + /** + * @var string modalConfirmButtonSelector + * CSS classes selector for the disable-confirm button + */ + modalConfirmButtonSelector: '.disableConfirm', + /** + * @var string modalCancelButtonSelector + * CSS classes selector for the disable-cancel button + */ + modalCancelButtonSelector: '.disableCancel', /** * @var string errorMessageClass * CSS classes for the error message element */ - errorMessageClass: 'alert--content' + errorMessageClass: 'alert--content', + /** + * @var string modalErrorContainerSelector + * CSS classes for the error message container in the modal + */ + modalErrorContainerSelector: '.modal-error-container', }, init: function () { var me = this; me.applyDataAttributes(); + me.modalContent = $(me.opts.modalSelector).html() || ''; me.$el.on('click', $.proxy(me.enableDisableButtonClick, me)); }, enableDisableButtonClick: function () { @@ -39,7 +60,32 @@ if (0 === me.opts.adyenStoredMethodId.length) { return; } + + if('' === me.modalContent){ + return; + } + me.modal = $.modal.open(me.modalContent, { + showCloseButton: true, + closeOnOverlay: false, + additionalClass: 'adyen-modal disable-token-confirmation' + }); + me.buttonConfirm = $(me.opts.modalConfirmButtonSelector); + me.buttonConfirm.on('click', $.proxy(me.runDisableTokenCall, me)); + me.buttonCancel = $(me.opts.modalCancelButtonSelector); + me.buttonCancel.on('click', $.proxy(me.closeModal, me)); + }, + closeModal: function () { + var me = this; + if(!me.modal){ + return; + } + me.modal.close(); + }, + runDisableTokenCall: function () { + var me = this; $.loadingIndicator.open(); + $.loadingIndicator.loader.$loader.addClass('over-modal'); + $.post({ url: me.opts.adyenDisableTokenUrl, dataType: 'json', @@ -58,7 +104,7 @@ $(me.opts.errorClassSelector).remove(); var error = $('
').addClass(me.opts.errorClass); error.append($('
').addClass(me.opts.errorMessageClass).html(message)); - me.$el.parent().append(error); + $(me.opts.modalErrorContainerSelector).append(error); } }); })(jQuery); diff --git a/Resources/frontend/js/jquery.adyen-payment-selection.js b/Resources/frontend/js/jquery.adyen-payment-selection.js index f76f1102..df54ef18 100644 --- a/Resources/frontend/js/jquery.adyen-payment-selection.js +++ b/Resources/frontend/js/jquery.adyen-payment-selection.js @@ -10,7 +10,7 @@ adyenOrderTotal: '', adyenOrderCurrency: '', resetSessionUrl: '', - adyenConfigAjaxUrl: '/frontend/adyenconfig/index', + adyenConfigAjaxUrl: '', /** * Fallback environment variable * @@ -198,26 +198,7 @@ setConfig: function () { var me = this; - $.ajax({ - method: 'GET', - async: false, - dataType: 'json', - url: me.opts.adyenConfigAjaxUrl, - success: function (response) { - if (response['status'] === 'success') { - me.opts.shopLocale = response['shopLocale']; - me.opts.adyenClientKey = response['clientKey']; - me.opts.adyenEnvironment = response['environment']; - me.opts.enrichedPaymentMethods = response['enrichedPaymentMethods']; - me.opts.adyenOrderTotal = response['adyenOrderTotal']; - me.opts.adyenOrderCurrency = response['adyenOrderCurrency']; - } else { - me.addAdyenError(response['content']); - } - - $.loadingIndicator.close(); - } - }); + me.fetchAdyenConfig(); var adyenPaymentMethodsResponse = me.opts.enrichedPaymentMethods.reduce( function (rawAdyen, enrichedPaymentMethod) { @@ -240,6 +221,30 @@ }; me.saveAdyenConfigInSession(me.adyenConfiguration); }, + fetchAdyenConfig: function () { + var me = this; + + return $.ajax({ + method: 'GET', + async: false, + dataType: 'json', + url: me.opts.adyenConfigAjaxUrl, + success: function (response) { + if (response['status'] === 'success') { + me.opts.shopLocale = response['shopLocale']; + me.opts.adyenClientKey = response['clientKey']; + me.opts.adyenEnvironment = response['environment']; + me.opts.enrichedPaymentMethods = response['enrichedPaymentMethods']; + me.opts.adyenOrderTotal = response['adyenOrderTotal']; + me.opts.adyenOrderCurrency = response['adyenOrderCurrency']; + } else { + me.addAdyenError(response['content']); + } + + $.loadingIndicator.close(); + } + }); + }, getCurrentComponentId: function (selectedPaymentElementId) { return 'component-' + selectedPaymentElementId; }, @@ -278,10 +283,13 @@ var adyenCheckoutData = me.__buildCheckoutComponentData(paymentMethod); if (this.__isApplePayPaymentMethod(paymentMethod)) { + me.setConfig(); me.setPaymentSession(me.__buildMinimalState(paymentMethod)); + adyenCheckoutData = me.__buildCheckoutComponentData(paymentMethod); } if ('paywithgoogle' === paymentMethod.adyenType) { + me.setConfig(); me.setPaymentSession(me.__buildMinimalState(paymentMethod)); me.handleComponentPayWithGoogle(); return; diff --git a/Resources/frontend/less/all.less b/Resources/frontend/less/all.less index 6df53d6b..cab1f7fd 100644 --- a/Resources/frontend/less/all.less +++ b/Resources/frontend/less/all.less @@ -27,6 +27,25 @@ .adyen-modal .content { padding: 20px; + + .modal-error-container { + margin-top: 2em; + } +} + +.over-modal { + z-index: 7000; +} + +.disable-token-confirmation { + height: auto; + max-height: 18em; + + .buttons-container { + display: flex; + justify-content: space-evenly; + margin-top: 2em; + } } .alert.is--adyen-error { diff --git a/Resources/services/components.xml b/Resources/services/components.xml index 1512826a..c4d2492a 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -10,6 +10,7 @@ + diff --git a/Resources/services/managers.xml b/Resources/services/managers.xml index dfbd4728..788e9ebd 100644 --- a/Resources/services/managers.xml +++ b/Resources/services/managers.xml @@ -20,6 +20,7 @@ + diff --git a/Resources/services/shopware.xml b/Resources/services/shopware.xml index 490cb309..d53aae49 100644 --- a/Resources/services/shopware.xml +++ b/Resources/services/shopware.xml @@ -7,5 +7,9 @@ + + + + diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index a05c526f..3bd2d050 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -66,6 +66,7 @@ + diff --git a/Resources/services/validators.xml b/Resources/services/validators.xml index 4311d685..07c15785 100644 --- a/Resources/services/validators.xml +++ b/Resources/services/validators.xml @@ -30,4 +30,4 @@ service('models').getRepository('Shopware\\Models\\Shop\\Shop') - \ No newline at end of file + diff --git a/Resources/views/frontend/checkout/adyen_configuration.tpl b/Resources/views/frontend/checkout/adyen_configuration.tpl index ca36ef3a..6cd0cca3 100644 --- a/Resources/views/frontend/checkout/adyen_configuration.tpl +++ b/Resources/views/frontend/checkout/adyen_configuration.tpl @@ -1,4 +1,5 @@
diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl index 795d6fe9..412bc07a 100644 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -34,3 +34,21 @@ {/if} {/block} {/block} + +{block name="frontend_register_payment_fieldset"} + {$smarty.block.parent} +
+
+

{s name='adyenDisableTokenConfirmationMessage'}Are you sure to remove the stored payment method?{/s}

+
+ + +
+ +
+
+{/block} diff --git a/Shopware/Provider/CheckoutBasketProvider.php b/Shopware/Provider/CheckoutBasketProvider.php new file mode 100644 index 00000000..48562b8d --- /dev/null +++ b/Shopware/Provider/CheckoutBasketProvider.php @@ -0,0 +1,26 @@ +container = $container; + $this->view = new \Enlight_View_Default($engine); + $this->init(); + + parent::__construct(); + } + + public function __invoke($mergeProportional = true): array + { + return $this->getBasket($mergeProportional); + } +} diff --git a/Shopware/Provider/CheckoutBasketProviderInterface.php b/Shopware/Provider/CheckoutBasketProviderInterface.php new file mode 100644 index 00000000..3014f088 --- /dev/null +++ b/Shopware/Provider/CheckoutBasketProviderInterface.php @@ -0,0 +1,10 @@ +getId() => array_replace($paymentMean->getRaw(), [ - 'name' => Sanitize::escape($paymentMean->getValue('name')), - 'description' => Sanitize::escape($paymentMean->getValue('description')), - 'additionaldescription' => Sanitize::escapeWithQuotes($paymentMean->getValue('additionaldescription')), + 'name' => $paymentMean->getValue('name'), + 'description' => $paymentMean->getValue('description'), + 'additionaldescription' => $paymentMean->getValue('additionaldescription'), ]), ]; } diff --git a/Subscriber/CheckoutSubscriber.php b/Subscriber/CheckoutSubscriber.php index 3220abe4..e62c138b 100644 --- a/Subscriber/CheckoutSubscriber.php +++ b/Subscriber/CheckoutSubscriber.php @@ -12,6 +12,7 @@ use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMean; use AdyenPayment\Serializer\PaymentMeanCollectionSerializer; +use AdyenPayment\Shopware\Provider\CheckoutBasketProviderInterface; use Enlight\Event\SubscriberInterface; final class CheckoutSubscriber implements SubscriberInterface @@ -22,6 +23,7 @@ final class CheckoutSubscriber implements SubscriberInterface private EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider; private PaymentMethodOptionsBuilderInterface $paymentMethodOptionsBuilder; private PaymentMeanCollectionSerializer $paymentMeanCollectionSerializer; + private CheckoutBasketProviderInterface $checkoutBasketProvider; public function __construct( Configuration $configuration, @@ -29,7 +31,8 @@ public function __construct( DataConversion $dataConversion, EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider, PaymentMethodOptionsBuilderInterface $paymentMethodOptionsBuilder, - PaymentMeanCollectionSerializer $paymentMeanCollectionSerializer + PaymentMeanCollectionSerializer $paymentMeanCollectionSerializer, + CheckoutBasketProviderInterface $checkoutBasketProvider ) { $this->configuration = $configuration; $this->paymentMethodService = $paymentMethodService; @@ -37,6 +40,7 @@ public function __construct( $this->enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; $this->paymentMethodOptionsBuilder = $paymentMethodOptionsBuilder; $this->paymentMeanCollectionSerializer = $paymentMeanCollectionSerializer; + $this->checkoutBasketProvider = $checkoutBasketProvider; } public static function getSubscribedEvents(): array @@ -63,7 +67,8 @@ private function checkBasketAmount(\Enlight_Controller_Action $subject): void return; } - $basket = $subject->View()->sBasket; + $basket = ($this->checkoutBasketProvider)(); + if (!$basket) { return; } diff --git a/Utils/Sanitize.php b/Utils/Sanitize.php index 9c15fef7..41064702 100644 --- a/Utils/Sanitize.php +++ b/Utils/Sanitize.php @@ -15,9 +15,4 @@ public static function escape(string $raw): string { return htmlspecialchars($raw, ENT_NOQUOTES); } - - public static function escapeWithQuotes(string $raw): string - { - return htmlspecialchars($raw, ENT_QUOTES); - } } diff --git a/plugin.xml b/plugin.xml index 509a0e96..4e10edab 100644 --- a/plugin.xml +++ b/plugin.xml @@ -4,7 +4,7 @@ - 3.5.0 + 3.8.0 Adyen Adyen https://adyen.com @@ -317,4 +317,28 @@ * functionality to remove stored payment methods / tokens + + + * Apple Pay amount mismatch issue is solved (issue occured on change shipping/payment where basket was being miscalculated). + * Removed html sanitizing on checkout (using json response instead of html data attribute), so design can be tweaked on payment method. + + + * Das Problem mit der Nichtübereinstimmung des Apple Pay-Betrags wurde behoben (das Problem trat bei der Änderung des Versands/der Zahlung auf, bei der der Warenkorb falsch berechnet wurde). + * HTML-Bereinigung beim Checkout entfernt (unter Verwendung von JSON-Antwort anstelle des HTML-Datenattributs), sodass das Design an der Zahlungsmethode angepasst werden kann. + + + + + * USP - Confirm modal + * Fix: Duplicate Webhook Notifications + * Fix: Mismatch of Basket Amount for guest and user accounts on payment + * Feature: Allow additional description for payment methods (with fallback to translations) + + + * USP - Confirm modal + * Fix: Duplicate Webhook Notifications + * Fix: Mismatch of Basket Amount for guest and user accounts on payment + * Feature: Allow additional description for payment methods (with fallback to translations) + + diff --git a/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php b/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php index d46adb1d..0ecade90 100644 --- a/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php +++ b/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php @@ -47,7 +47,7 @@ public function it_will_enrich_a_payment_method_without_stored_method_data(): vo { $shopwareMethod = [ 'id' => 'shopware-method-id', - 'additionaldescription' => '', + 'additionaldescription' => $description = 'Adyen Method', 'image' => '', ]; $paymentMethod = PaymentMethod::fromRaw($rawData = [ @@ -78,7 +78,10 @@ public function it_will_enrich_a_payment_method_without_stored_method_data(): vo /** @test */ public function it_will_enrich_a_payment_method_with_stored_method_data(): void { - $shopwareMethod = ['id' => $shopwareMethodId = 'shopware-method-id']; + $shopwareMethod = [ + 'id' => $shopwareMethodId = 'shopware-method-id', + 'additionaldescription' => $description = 'Stored Method', + ]; $paymentMethod = PaymentMethod::fromRaw($rawData = [ 'id' => $storedMethodId = 'stored_method_id', 'name' => $storedMethodName = 'stored method name', @@ -87,7 +90,7 @@ public function it_will_enrich_a_payment_method_with_stored_method_data(): void 'lastFour' => $lastFour = '1234', ]); $snippetsNamespace = $this->prophesize(\Enlight_Components_Snippet_Namespace::class); - $snippetsNamespace->get($paymentMethod->adyenType()->type())->willReturn($description = 'Stored Method'); + $snippetsNamespace->get($paymentMethod->adyenType()->type())->willReturn($description); $snippetsNamespace->get('CardNumberEndingOn', $text = 'Card number ending on', true)->willReturn($text); $this->snippets->getNamespace('adyen/method/description')->willReturn($snippetsNamespace); $this->snippets->getNamespace('adyen/checkout/payment')->willReturn($snippetsNamespace); diff --git a/tests/Unit/Exceptions/DuplicateNotificationExceptionTest.php b/tests/Unit/Exceptions/DuplicateNotificationExceptionTest.php new file mode 100644 index 00000000..9b1231ce --- /dev/null +++ b/tests/Unit/Exceptions/DuplicateNotificationExceptionTest.php @@ -0,0 +1,49 @@ +exception = new DuplicateNotificationException(); + } + + /** @test */ + public function is_a_runtime_exception(): void + { + self::assertInstanceOf(\RuntimeException::class, $this->exception); + } + + /** @test */ + public function it_can_be_constructed_with_a_notification(): void + { + $notification = new Notification(); + $notification + ->setId($id = 1) + ->setOrderId($orderId = 2) + ->setPspReference($pspReference = 'PSP_REF_1') + ->setStatus('received') + ->setPaymentMethod('mc') + ->setEventCode('AUTHORISATION') + ->setSuccess(true) + ->setMerchantAccountCode('Adyen-test') + ->setAmountValue(4598.0000) + ->setAmountCurrency('EUR'); + + $exception = DuplicateNotificationException::withNotification($notification); + + self::assertInstanceOf(DuplicateNotificationException::class, $exception); + self::assertEquals('Duplicate notification is not handled. Notification with id: "1", orderId: "2", pspReference: "PSP_REF_1", status: "received", paymentMethod: "mc", eventCode: "AUTHORISATION", success: "1", merchantAccountCode: "Adyen-test", amountValue: "4598", amountCurrency: "EUR"', + $exception->getMessage() + ); + } +} diff --git a/tests/Unit/Shopware/Controllers/Frontend/CheckoutTest.php b/tests/Unit/Shopware/Controllers/Frontend/CheckoutTest.php new file mode 100644 index 00000000..7fa26fa1 --- /dev/null +++ b/tests/Unit/Shopware/Controllers/Frontend/CheckoutTest.php @@ -0,0 +1,155 @@ +admin = $this->prophesize(\sAdmin::class); + $this->basket = $this->prophesize(\sBasket::class); + $this->session = $this->prophesize(\Enlight_Components_Session_Namespace::class); + $this->container = $this->prophesize(Container::class); + $this->engine = $this->prophesize(Enlight_Template_Manager::class); + $this->view = new \Enlight_View_Default($this->engine->reveal()); + $this->checkoutController = new MockCheckout(); + } + + /** @test */ + public function it_is_csrf_get_protection_aware(): void + { + $this->assertInstanceOf(CSRFGetProtectionAware::class, $this->checkoutController); + } + + /** @test */ + public function it_returns_complete_basket_data_to_view(): void + { + $this->markTestIncomplete(); +// $this->view->setScope(['test']); +// $this->view->assign('sUserData', ['additional' => ['countryShipping' => null]]); + + $this->checkoutController->setAdyenMockProperties( + $this->admin->reveal(), + $this->basket->reveal(), + $this->session->reveal(), + $this->container->reveal(), +// $this->view + ); + + $countryList = [ $country = [ + "id" => 2, + "name" => "Deutschland", + "iso" => "DE", + "en" => "GERMANY", + "description" => "", + "position" => 1, + "active" => true, + "iso3" => "DEU", + "taxFree" => false, + "taxFreeForVatId" => false, + "vatIdCheck" => false, + "displayStateSelection" => false, + "requiresStateSelection" => false, + "allowShipping" => true, + "states" => [], + "areaId" => 1, + "attributes" => [], + "countryname" => "Deutschland", + "countryiso" => "DE", + "countryen" => "GERMANY", + "taxfree" => false, + "taxfree_ustid" => false, + "taxfree_ustid_checked" => false, + "display_state_in_registration" => false, + "force_state_in_registration" => false, + "areaID" => 1, + "allow_shipping" => true, + "flag" => false + ]]; + + $this->admin->sGetCountryList()->willReturn($countryList); +// $this->admin->sGetCountryList()->shouldBeCalledOnce(); + + $shop = new Shop(); + $currency = new Currency(); + $currency->setCurrency('EUR'); + $currency->setFactor(2); + $shop->setCurrency($currency); + $shop = $this->container->get('shop')->willReturn($shop); + + $positions = [ + new Price( + (float) $price = ($endPrice = 121.00) * ($quantity = 2), + (float) $netPrice = ($netPrice = 100.00 * $quantity), + (float) $taxRate = 21.0, + null + ) + ]; + $basketHelper = $this->prophesize(BasketHelperInterface::class); + $basketHelper->getPositionPrices(Argument::cetera())->willReturn($positions); + $positions = $this->container->get(BasketHelperInterface::class)->willReturn($basketHelper); + + $proportionalTaxCalculator = $this->prophesize(ProportionalTaxCalculatorInterface::class); + $taxCalculator = $this->container->get('shopware.cart.proportional_tax_calculator') + ->willReturn($proportionalTaxCalculator); + $proportionalTaxCalculator->hasDifferentTaxes(Argument::cetera()) + ->willReturn(true); + + $configComponent = $this->prophesize(\Shopware_Components_Config::class); + $config = $this->container->get(\Shopware_Components_Config::class) + ->willReturn($configComponent); + + $basketResult = $this->checkoutController->getBasket(); + } +} + +class MockCheckout extends \Shopware_Controllers_Frontend_Checkout +{ + + public function setAdyenMockProperties($admin, $basket, $session, $container, $view): void + { + $this->admin = $admin; + $this->basket = $basket; + $this->session = $session; + $this->container = $container; + $this->view = $view; + } +} diff --git a/tests/Unit/Shopware/Serializer/SwPaymentMeanSerializerTest.php b/tests/Unit/Shopware/Serializer/SwPaymentMeanSerializerTest.php index 1ffd2f91..4022e29c 100644 --- a/tests/Unit/Shopware/Serializer/SwPaymentMeanSerializerTest.php +++ b/tests/Unit/Shopware/Serializer/SwPaymentMeanSerializerTest.php @@ -55,9 +55,9 @@ public function it_can_serialize_html(): void $id => [ 'id' => $id, 'source' => $source, - 'name' => '<some-tag> a name</some-tag> "quoted"', - 'description' => "description and<a href='test'>a link</a>", - 'additionaldescription' => 'additional <div>a div</div> and <a href='test'>link</a>', + 'name' => ' a name "quoted"', + 'description' => "description anda link", + 'additionaldescription' => "additional
a div
and link", ], ], $result); } diff --git a/tests/Unit/Utils/SanitizeTest.php b/tests/Unit/Utils/SanitizeTest.php index 413fe281..30c529e5 100644 --- a/tests/Unit/Utils/SanitizeTest.php +++ b/tests/Unit/Utils/SanitizeTest.php @@ -24,12 +24,4 @@ public function it_can_escape_without_quotes(): void $this->assertEquals("<a href='test'>Test</a>", $result); } - - /** @test */ - public function it_can_escape_with_quotes(): void - { - $result = Sanitize::escapeWithQuotes("Test"); - - $this->assertEquals('<a href='test'>Test</a>', $result); - } }