From 396b9b1de71a4c49743fac8b662c80b752934df1 Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Tue, 1 Feb 2022 14:54:00 +0100 Subject: [PATCH 001/136] ASW-0 update pipline for master branch --- bitbucket-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index e7e57b43..a0c4692b 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -21,4 +21,5 @@ pipelines: script: - echo "memory_limit=-1" >> /usr/local/etc/php/php.ini - composer install --prefer-dist + - composer install --prefer-dist -d ./tools/ - php ./vendor/bin/grumphp run --testsuite="code-compatibility" From fc161b538b67e62a7b786a692a60e3cf7b2fda6e Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Fri, 24 Dec 2021 14:28:14 +0100 Subject: [PATCH 002/136] ASW-436 fix nullable data from attribute, add enriched test --- .../EnrichedPaymentMeanProvider.php | 10 +- Components/Adyen/PaymentMethodService.php | 2 +- .../Adyen/PaymentMethodServiceInterface.php | 24 ++ Models/Payment/PaymentMethod.php | 4 +- grumphp.yml.dist | 2 +- .../EnrichedPaymentMeanProviderTest.php | 252 ++++++++++++++++++ 6 files changed, 285 insertions(+), 9 deletions(-) create mode 100644 Components/Adyen/PaymentMethodServiceInterface.php create mode 100644 tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php diff --git a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php index 74ed0efe..dc3a6cca 100644 --- a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php @@ -7,7 +7,7 @@ use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Components\Adyen\Builder\PaymentMethodOptionsBuilderInterface; -use AdyenPayment\Components\Adyen\PaymentMethodService; +use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use AdyenPayment\Enricher\Payment\PaymentMethodEnricherInterface; use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMean; @@ -15,12 +15,12 @@ final class EnrichedPaymentMeanProvider implements EnrichedPaymentMeanProviderInterface { - private PaymentMethodService $paymentMethodService; + private PaymentMethodServiceInterface $paymentMethodService; private PaymentMethodOptionsBuilderInterface $paymentMethodOptionsBuilder; private PaymentMethodEnricherInterface $paymentMethodEnricher; public function __construct( - PaymentMethodService $paymentMethodService, + PaymentMethodServiceInterface $paymentMethodService, PaymentMethodOptionsBuilderInterface $paymentMethodOptionsBuilder, PaymentMethodEnricherInterface $paymentMethodEnricher ) { @@ -59,9 +59,9 @@ static function(PaymentMean $shopwareMethod) use ($adyenPaymentMethods, $enriche return $shopwareMethod; } - $identifierOrStoredId = '' !== (string) $attribute->get(AdyenPayment::ADYEN_STORED_METHOD_ID) + $identifierOrStoredId = (string) ('' !== (string) $attribute->get(AdyenPayment::ADYEN_STORED_METHOD_ID) ? $attribute->get(AdyenPayment::ADYEN_STORED_METHOD_ID) - : $attribute->get(AdyenPayment::ADYEN_CODE); + : $attribute->get(AdyenPayment::ADYEN_CODE)); $paymentMethod = $adyenPaymentMethods->fetchByIdentifierOrStoredId($identifierOrStoredId); diff --git a/Components/Adyen/PaymentMethodService.php b/Components/Adyen/PaymentMethodService.php index 4d5e3f36..0200b269 100644 --- a/Components/Adyen/PaymentMethodService.php +++ b/Components/Adyen/PaymentMethodService.php @@ -15,7 +15,7 @@ use Shopware\Components\Model\ModelManager; use Shopware\Models\Customer\Customer; -final class PaymentMethodService +final class PaymentMethodService implements PaymentMethodServiceInterface { /** @todo cleanup the public const (unify the services) */ public const IMPORT_LOCALE = 'en_GB'; diff --git a/Components/Adyen/PaymentMethodServiceInterface.php b/Components/Adyen/PaymentMethodServiceInterface.php new file mode 100644 index 00000000..ace594de --- /dev/null +++ b/Components/Adyen/PaymentMethodServiceInterface.php @@ -0,0 +1,24 @@ +code = mb_strtolower(sprintf('%s_%s', $this->type->type(), - Sanitize::removeNonWord($code) + Sanitize::removeNonWord($name) )); return $new; diff --git a/grumphp.yml.dist b/grumphp.yml.dist index 87435f22..537b226c 100644 --- a/grumphp.yml.dist +++ b/grumphp.yml.dist @@ -25,7 +25,7 @@ grumphp: - 'die(' - 'dump(' - 'exit;' - - "\\bdd\\b\\(" + - "\\bdd\\b(" triggered_by: [php,js,tpl] file_size: max_size: 5M diff --git a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php new file mode 100644 index 00000000..a83d9f2d --- /dev/null +++ b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php @@ -0,0 +1,252 @@ +paymentMethodService = $this->prophesize(PaymentMethodServiceInterface::class); + $this->paymentMethodOptionsBuilder = $this->prophesize(PaymentMethodOptionsBuilderInterface::class); + $this->paymentMethodEnricher = $this->prophesize(PaymentMethodEnricherInterface::class); + + $this->provider = new EnrichedPaymentMeanProvider( + $this->paymentMethodService->reveal(), + $this->paymentMethodOptionsBuilder->reveal(), + $this->paymentMethodEnricher->reveal() + ); + } + + /** @test */ + public function it_is_an_enriched_payment_mean_provider(): void + { + $this->assertInstanceOf(EnrichedPaymentMeanProviderInterface::class, $this->provider); + } + + /** @test */ + public function it_does_not_enrich_on_empty_cart_value_and_excludes_adyen_methods(): void + { + $paymentMeans = new PaymentMeanCollection( + $paymentMeanOne = PaymentMean::createFromShopwareArray([ + 'id' => 1, + 'source' => SourceType::shopwareDefault()->getType(), + ]), + PaymentMean::createFromShopwareArray([ + 'id' => 2, + 'source' => SourceType::adyen()->getType(), + ]), + ); + + $this->paymentMethodOptionsBuilder->__invoke()->willReturn(['value' => 0.0]); + $this->paymentMethodService->getPaymentMethods(Argument::cetera())->shouldNotBeCalled(); + $this->paymentMethodEnricher->__invoke(Argument::cetera())->shouldNotBeCalled(); + + $result = $this->provider->__invoke($paymentMeans); + $this->assertInstanceOf(PaymentMeanCollection::class, $result); + $this->assertCount(1, $result); + $this->assertSame($paymentMeanOne, iterator_to_array($result)[0]); + } + + /** @test */ + public function it_does_not_enrich_non_adyen_methods(): void + { + $adyenIdentifier = sprintf('%s_%s', $adyenType = 'non', $adyenName = 'adyen'); + $paymentMeans = new PaymentMeanCollection( + $paymentMean = PaymentMean::createFromShopwareArray([ + 'id' => 17, + 'source' => SourceType::shopwareDefault()->getType(), + 'attribute' => new Attribute([ + 'adyen_type' => $adyenIdentifier, + 'adyen_stored_method_id' => null, + ]), + ]), + ); + + // filled with a matching identifier, to catch if the early returns fails + $adyenPaymentMethods = new PaymentMethodCollection( + PaymentMethod::fromRaw(['type' => $adyenType])->withCode($adyenName), + ); + + $this->paymentMethodOptionsBuilder->__invoke()->willReturn([ + 'countryCode' => $countryCode = 'BE', + 'currency' => $currency = 'EUR', + 'value' => $value = 17.7, + ]); + $this->paymentMethodService->getPaymentMethods($countryCode, $currency, $value) + ->willReturn($adyenPaymentMethods); + $this->paymentMethodEnricher->__invoke(Argument::cetera())->shouldNotBeCalled(); + + $result = $this->provider->__invoke($paymentMeans); + $this->assertInstanceOf(PaymentMeanCollection::class, $result); + $this->assertCount(1, $result); + $this->assertSame($paymentMean, iterator_to_array($result)[0]); + } + + /** @test */ + public function it_does_not_enrich_payment_means_without_attribute(): void + { + $paymentMeans = new PaymentMeanCollection( + $paymentMean = PaymentMean::createFromShopwareArray([ + 'id' => 19, + 'source' => SourceType::shopwareDefault()->getType(), + ]), + $paymentMean = PaymentMean::createFromShopwareArray([ + 'id' => 21, + 'source' => SourceType::adyen()->getType(), + ]), + ); + + $this->paymentMethodOptionsBuilder->__invoke()->willReturn([ + 'countryCode' => $countryCode = 'BE', + 'currency' => $currency = 'EUR', + 'value' => $value = 17.7, + ]); + $this->paymentMethodService->getPaymentMethods($countryCode, $currency, $value) + ->willReturn(new PaymentMethodCollection()); + $this->paymentMethodEnricher->__invoke(Argument::cetera())->shouldNotBeCalled(); + + $result = $this->provider->__invoke($paymentMeans); + $this->assertInstanceOf(PaymentMeanCollection::class, $result); + $this->assertCount(2, $result); + $this->assertNotSame($paymentMeans, $result); + $this->assertEquals($paymentMeans, $result); + } + + /** @test */ + public function it_does_not_enrich_payment_means_with_attribute_null_values(): void + { + $paymentMeans = new PaymentMeanCollection( + $paymentMean = PaymentMean::createFromShopwareArray([ + 'id' => 9, + 'source' => SourceType::adyen()->getType(), + 'attribute' => new Attribute([ + 'adyen_type' => null, + 'adyen_stored_method_id' => null, + ]), + ]), + ); + + $this->paymentMethodOptionsBuilder->__invoke()->willReturn([ + 'countryCode' => $countryCode = 'GB', + 'currency' => $currency = 'GBP', + 'value' => $value = 9.39, + ]); + $this->paymentMethodService->getPaymentMethods($countryCode, $currency, $value) + ->willReturn(new PaymentMethodCollection()); + $this->paymentMethodEnricher->__invoke(Argument::cetera())->shouldNotBeCalled(); + + $result = $this->provider->__invoke($paymentMeans); + $this->assertInstanceOf(PaymentMeanCollection::class, $result); + $this->assertCount(0, $result); + } + + /** @test */ + public function it_removes_adyen_payment_means_without_matching_adyen_payment_method(): void + { + $paymentMeans = new PaymentMeanCollection( + $paymentMean = PaymentMean::createFromShopwareArray([ + 'id' => 25, + 'source' => SourceType::adyen()->getType(), + 'attribute' => new Attribute([ + 'adyen_type' => 'non_matching_adyen_identifier', + 'adyen_stored_method_id' => null, + ]), + ]), + ); + + $this->paymentMethodOptionsBuilder->__invoke()->willReturn([ + 'countryCode' => $countryCode = 'BE', + 'currency' => $currency = 'EUR', + 'value' => $value = 17.7, + ]); + $this->paymentMethodService->getPaymentMethods($countryCode, $currency, $value) + ->willReturn(new PaymentMethodCollection()); + $this->paymentMethodEnricher->__invoke(Argument::cetera())->shouldNotBeCalled(); + + $result = $this->provider->__invoke($paymentMeans); + $this->assertInstanceOf(PaymentMeanCollection::class, $result); + $this->assertCount(0, $result); + } + + /** @test */ + public function it_enriches_adyen_payment_methods(): void + { + $adyenIdentifier = sprintf('%s_%s', $adyenType = 'bcmc', $adyenName = 'adyen_name'); + $paymentMeans = new PaymentMeanCollection( + $paymentMean = PaymentMean::createFromShopwareArray($raw = [ + 'id' => $id = 15, + 'source' => $source = SourceType::adyen()->getType(), + 'attribute' => new Attribute([ + 'adyen_type' => $adyenIdentifier, + 'adyen_stored_method_id' => null, + ]), + ]), + ); + + $adyenPaymentMethods = new PaymentMethodCollection( + $paymentMethod = PaymentMethod::fromRaw([ + 'type' => $adyenType, + ])->withCode($adyenName), + $storedPaymentMethod = PaymentMethod::fromRaw([ + 'id' => 'adyen-stored-payment-method-id', + 'type' => 'scheme', + ]), + ); + + $this->paymentMethodOptionsBuilder->__invoke()->willReturn([ + 'countryCode' => $countryCode = 'DE', + 'currency' => $currency = 'EUR', + 'value' => $value = 15.0, + ]); + $this->paymentMethodService->getPaymentMethods($countryCode, $currency, $value) + ->willReturn($adyenPaymentMethods); + + $this->paymentMethodEnricher->__invoke($raw, $paymentMethod)->willReturn($rawEnriched = [ + 'id' => $id, + 'source' => $source, + 'enriched' => true, + 'adyenType' => $adyenType, + ]); + + $result = $this->provider->__invoke($paymentMeans); + $this->assertInstanceOf(PaymentMeanCollection::class, $result); + $this->assertCount(1, $result); + $this->assertEquals($rawEnriched, iterator_to_array($result)[0]->getRaw()); + } +} From ae2b1b49becc94bce804641ff79bd1ca21d753a0 Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Fri, 24 Dec 2021 15:14:13 +0100 Subject: [PATCH 003/136] ASW-436 handle exceptions --- .../EnrichedPaymentMeanProvider.php | 1 - .../TraceableEnrichedPaymentMeanProvider.php | 36 +++++++++ Resources/services/components.xml | 37 +++++---- ...aceableEnrichedPaymentMeanProviderTest.php | 80 +++++++++++++++++++ 4 files changed, 138 insertions(+), 16 deletions(-) create mode 100644 Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProvider.php create mode 100644 tests/Unit/Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProviderTest.php diff --git a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php index dc3a6cca..d400b4b5 100644 --- a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php @@ -64,7 +64,6 @@ static function(PaymentMean $shopwareMethod) use ($adyenPaymentMethods, $enriche : $attribute->get(AdyenPayment::ADYEN_CODE)); $paymentMethod = $adyenPaymentMethods->fetchByIdentifierOrStoredId($identifierOrStoredId); - if (null === $paymentMethod) { return null; } diff --git a/Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProvider.php new file mode 100644 index 00000000..c83e1cb9 --- /dev/null +++ b/Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProvider.php @@ -0,0 +1,36 @@ +enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + $this->logger = $logger; + } + + /** + * @throws \Adyen\AdyenException + */ + public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollection + { + try { + return ($this->enrichedPaymentMeanProvider)($paymentMeans); + } catch (\Exception $exception) { + $this->logger->critical($exception->getMessage(), ['exception' => $exception]); + } + + return new PaymentMeanCollection(); + } +} diff --git a/Resources/services/components.xml b/Resources/services/components.xml index df611da2..94f57b34 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -31,7 +31,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -61,7 +61,8 @@ - + @@ -71,21 +72,21 @@ - + - - - + + + - + - - - - - + + + + + @@ -160,8 +161,9 @@ - - + + @@ -169,6 +171,11 @@ + + + + diff --git a/tests/Unit/Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProviderTest.php new file mode 100644 index 00000000..40499328 --- /dev/null +++ b/tests/Unit/Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProviderTest.php @@ -0,0 +1,80 @@ +enrichedPaymentMeanProvider = $this->prophesize(EnrichedPaymentMeanProviderInterface::class); + $this->logger = $this->prophesize(LoggerInterface::class); + + $this->provider = new TraceableEnrichedPaymentMeanProvider( + $this->enrichedPaymentMeanProvider->reveal(), + $this->logger->reveal() + ); + } + + /** @test */ + public function it_provides_enriched_payment_means(): void + { + $paymentMeans = new PaymentMeanCollection( + $paymentMean = PaymentMean::createFromShopwareArray([ + 'source' => SourceType::adyen()->getType(), + ]) + ); + $this->enrichedPaymentMeanProvider->__invoke($paymentMeans)->willReturn( + $enriched = new PaymentMeanCollection($paymentMean) + ); + $this->logger->critical(Argument::cetera())->shouldNotBeCalled(); + + $result = $this->provider->__invoke($paymentMeans); + $this->assertSame($enriched, $result); + } + + /** @test */ + public function it_logs_silently_exceptions(): void + { + $paymentMeans = new PaymentMeanCollection( + $paymentMean = PaymentMean::createFromShopwareArray([ + 'source' => SourceType::adyen()->getType(), + ]) + ); + $this->enrichedPaymentMeanProvider->__invoke($paymentMeans)->willThrow( + $exception = new \Exception($message = 'invalid type') + ); + + $this->logger->critical($message, ['exception' => $exception])->shouldBeCalled(); + + $result = $this->provider->__invoke($paymentMeans); + $this->assertNotSame($paymentMeans, $result); + $this->assertInstanceOf(PaymentMeanCollection::class, $result); + $this->assertCount(0, $result); + } +} From 81627d3f3555f49a05c709903f848b0683d37076 Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Fri, 24 Dec 2021 16:01:18 +0100 Subject: [PATCH 004/136] ASW-436 clear config cache on backen api action --- Controllers/Backend/AdyenPaymentRefund.php | 6 ++++-- Controllers/Backend/ImportPaymentMethods.php | 8 +++++++- Controllers/Backend/TestAdyenApi.php | 7 ++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Controllers/Backend/AdyenPaymentRefund.php b/Controllers/Backend/AdyenPaymentRefund.php index ddf0cf98..f2a1ec30 100644 --- a/Controllers/Backend/AdyenPaymentRefund.php +++ b/Controllers/Backend/AdyenPaymentRefund.php @@ -1,5 +1,6 @@ Request()->getParam('orderId'); - $notificationManager = $this->get('AdyenPayment\Components\Adyen\RefundService'); + $notificationManager = $this->get(RefundService::class); + $refund = $notificationManager->doRefund($orderId); $this->View()->assign('refundReference', $refund->getPspReference()); @@ -21,7 +23,7 @@ public function refundAction(): void * * @psalm-return array{0: 'refund'} */ - public function getWhitelistedCSRFActions() + public function getWhitelistedCSRFActions(): array { return ['refund']; } diff --git a/Controllers/Backend/ImportPaymentMethods.php b/Controllers/Backend/ImportPaymentMethods.php index cbcee661..dcc5d88e 100644 --- a/Controllers/Backend/ImportPaymentMethods.php +++ b/Controllers/Backend/ImportPaymentMethods.php @@ -2,8 +2,10 @@ declare(strict_types=1); +use AdyenPayment\Import\PaymentMethodImporter; use AdyenPayment\Import\PaymentMethodImporterInterface; use Psr\Log\LoggerInterface; +use Shopware\Components\CacheManager; use Symfony\Component\HttpFoundation\Response; //phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps, Generic.Files.LineLength.TooLong @@ -11,6 +13,7 @@ class Shopware_Controllers_Backend_ImportPaymentMethods extends Shopware_Control { private PaymentMethodImporterInterface $paymentMethodImporter; private LoggerInterface $logger; + private CacheManager $cacheManager; /** * @return void @@ -19,13 +22,16 @@ public function preDispatch() { parent::preDispatch(); - $this->paymentMethodImporter = $this->get('AdyenPayment\Import\PaymentMethodImporter'); + $this->cacheManager = $this->get(CacheManager::class); + $this->paymentMethodImporter = $this->get(PaymentMethodImporter::class); $this->logger = $this->get('adyen_payment.logger'); } public function importAction(): void { try { + $this->cacheManager->clearConfigCache(); + $total = $success = 0; foreach ($this->paymentMethodImporter->importAll() as $result) { ++$total; diff --git a/Controllers/Backend/TestAdyenApi.php b/Controllers/Backend/TestAdyenApi.php index c7285e05..1ae672d3 100644 --- a/Controllers/Backend/TestAdyenApi.php +++ b/Controllers/Backend/TestAdyenApi.php @@ -3,6 +3,7 @@ use AdyenPayment\Components\Adyen\ApiConfigValidator; use AdyenPayment\Rule\AdyenApi\UsedFallbackConfigRule; use AdyenPayment\Rule\AdyenApi\UsedFallbackConfigRuleInterface; +use Shopware\Components\CacheManager; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Validator\ConstraintViolationInterface; @@ -11,11 +12,13 @@ class Shopware_Controllers_Backend_TestAdyenApi extends Shopware_Controllers_Bac { private ApiConfigValidator $apiConfigValidator; private UsedFallbackConfigRuleInterface $usedFallbackConfigRule; + private CacheManager $cacheManager; public function preDispatch(): void { parent::preDispatch(); + $this->cacheManager = $this->get(CacheManager::class); $this->apiConfigValidator = $this->get(ApiConfigValidator::class); $this->usedFallbackConfigRule = $this->get(UsedFallbackConfigRule::class); } @@ -23,6 +26,8 @@ public function preDispatch(): void public function runAction(): void { $shopId = (int) $this->request->get('shopId', 1); + $this->cacheManager->clearConfigCache(); + $violations = $this->apiConfigValidator->validate($shopId); if ($violations->count() > 0) { $this->response->setHttpResponseCode(Response::HTTP_BAD_REQUEST); @@ -40,7 +45,7 @@ static function (ConstraintViolationInterface $violation) { $this->response->setHttpResponseCode(Response::HTTP_OK); $this->View()->assign('responseText', sprintf( '%sAdyen API connection successful.', - $usedFallback ? "Fallback to main shop API configuration
" : '' + $usedFallback ? "Fallback to main shop API configuration
" : '' )); } } From 2c075968caf7286d509ab0bd8fa28f524f1f5e5d Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 24 Dec 2021 12:28:06 +0100 Subject: [PATCH 005/136] ASW-376 - Stored payment methods --- Collection/Payment/PaymentMethodCollection.php | 4 ++++ Components/BasketService.php | 2 +- Resources/frontend/js/jquery.adyen-payment-selection.js | 5 +---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Collection/Payment/PaymentMethodCollection.php b/Collection/Payment/PaymentMethodCollection.php index 00d865e8..c71fe9b1 100644 --- a/Collection/Payment/PaymentMethodCollection.php +++ b/Collection/Payment/PaymentMethodCollection.php @@ -39,6 +39,10 @@ public static function fromAdyenMethods(array $adyenMethods): self ...array_map( static fn(array $paymentMethod) => PaymentMethod::fromRaw($paymentMethod), $adyenMethods['paymentMethods'] ?? [] + ), + ...array_map( + static fn(array $paymentMethod) => PaymentMethod::fromRaw($paymentMethod), + $adyenMethods['storedPaymentMethods'] ?? [] ) ); } diff --git a/Components/BasketService.php b/Components/BasketService.php index 57242b07..14e58448 100644 --- a/Components/BasketService.php +++ b/Components/BasketService.php @@ -279,7 +279,7 @@ private function insertInToBasket(Detail $optionData): int 'currencyFactor' => Shopware()->Shop()->getCurrency()->getFactor(), ]); - return $this->db->lastInsertId(); + return (int) $this->db->lastInsertId(); } /** diff --git a/Resources/frontend/js/jquery.adyen-payment-selection.js b/Resources/frontend/js/jquery.adyen-payment-selection.js index 83964cf1..2f5f429d 100644 --- a/Resources/frontend/js/jquery.adyen-payment-selection.js +++ b/Resources/frontend/js/jquery.adyen-payment-selection.js @@ -503,10 +503,7 @@ * @private */ __enableStoreDetails: function (paymentMethod) { - // ignore property "paymentMethod.supportsRecurring" - // return 'scheme' === paymentMethod.adyenType; - // @fixme temporarily disable stored payment details - return false; + return 'scheme' === paymentMethod.adyenType; }, /** * Modify AdyenPaymentMethod with additional data for the web-component library From ea82a6f7a0bcc7426e36bd71f57aeb73bb404bcb Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 4 Jan 2022 10:51:00 +0100 Subject: [PATCH 006/136] ASW-376 - Unit test --- .../Payment/PaymentMethodCollectionTest.php | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php diff --git a/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php new file mode 100644 index 00000000..de3fdf91 --- /dev/null +++ b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php @@ -0,0 +1,44 @@ + 'someType']); + $result = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [$paymentMethodData]]); + + self::assertInstanceOf(PaymentMethodCollection::class, $result); + self::assertEquals($expectedMethod, $result->getIterator()->current()); + } + + /** @test */ + public function it_can_map_adyen_stored_payment_methods(): void + { + $expectedMethod = PaymentMethod::fromRaw($storedPaymentMethodData = ['type' => 'someType', 'id' => '1234']); + $result = PaymentMethodCollection::fromAdyenMethods(['storedPaymentMethods' => [$storedPaymentMethodData]]); + + self::assertInstanceOf(PaymentMethodCollection::class, $result); + self::assertEquals($expectedMethod, $result->getIterator()->current()); + } + + /** @test */ + public function it_can_map_adyen_stored_and_non_stored_payment_methods(): void + { + $result = PaymentMethodCollection::fromAdyenMethods([ + 'storedPaymentMethods' => [['id' => '1234']], + 'paymentMethods' => [['type' => 'someType']], + ]); + + self::assertInstanceOf(PaymentMethodCollection::class, $result); + self::assertEquals(2, $result->count()); + } +} From 97c9dcdf648ec0643000eb384ebccef0a2f71841 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 22 Dec 2021 07:51:25 +0100 Subject: [PATCH 007/136] ASW-375 - Stored payment umbrella installation --- AdyenPayment.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/AdyenPayment.php b/AdyenPayment.php index 81fd409d..7e74ed1c 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -7,6 +7,7 @@ namespace AdyenPayment; use AdyenPayment\Components\CompilerPass\NotificationProcessorCompilerPass; +use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Notification; use AdyenPayment\Models\PaymentInfo; use AdyenPayment\Models\Refund; @@ -14,11 +15,13 @@ use Doctrine\ORM\Tools\SchemaTool; use Shopware\Bundle\AttributeBundle\Service\TypeMapping; use Shopware\Components\Logger; +use Shopware\Components\Model\ModelManager; use Shopware\Components\Plugin; use Shopware\Components\Plugin\Context\DeactivateContext; use Shopware\Components\Plugin\Context\InstallContext; use Shopware\Components\Plugin\Context\UninstallContext; use Shopware\Components\Plugin\Context\UpdateContext; +use Shopware\Models\Payment\Payment; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -30,6 +33,7 @@ final class AdyenPayment extends Plugin public const NAME = 'AdyenPayment'; public const ADYEN_CODE = 'adyen_type'; public const ADYEN_STORED_METHOD_ID = 'adyen_stored_method_id'; + public const ADYEN_STORED_PAYMENT_UMBRELLA_CODE = 'adyen_stored_payment_umbrella'; public const SESSION_ADYEN_RESTRICT_EMAILS = 'adyenRestrictEmail'; public const SESSION_ADYEN_PAYMENT_INFO_ID = 'adyenPaymentInfoId'; @@ -82,6 +86,7 @@ private function loadServices(ContainerBuilder $container): void public function install(InstallContext $context): void { $this->installAttributes(); + $this->installStoredPaymentUmbrella($context); $tool = new SchemaTool($this->container->get('models')); $classes = $this->getModelMetaData(); @@ -91,6 +96,7 @@ public function install(InstallContext $context): void public function update(UpdateContext $context): void { $this->installAttributes(); + $this->installStoredPaymentUmbrella($context); $tool = new SchemaTool($this->container->get('models')); $classes = $this->getModelMetaData(); @@ -187,6 +193,30 @@ private function rebuildAttributeModels(): void ['s_user_attributes', 's_core_paymentmeans_attributes'] ); } + + private function installStoredPaymentUmbrella(InstallContext $context): void + { + $database = $this->container->get('db'); + /** @var ModelManager $modelsManager */ + $modelsManager = $this->container->get(ModelManager::class); + + $payment = new Payment(); + $payment->setActive(true); + $payment->setName(self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE); + $payment->setSource(SourceType::adyen()->getType()); + $payment->setHide(true); + $payment->setPluginId($context->getPlugin()->getId()); + $payment->setDescription('Stored Payment'); + $payment->setAdditionalDescription('Adyen Stored Payment'); + + $sql = 'SELECT `id` FROM `s_core_paymentmeans` WHERE `name` = "'.self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE.'"'; + $paymentId = $database->fetchRow($sql)['id'] ?? null; + + if (null === $paymentId) { + $modelsManager->persist($payment); + $modelsManager->flush($payment); + } + } } if (AdyenPayment::isPackage()) { From 36278b9b27241f0f3156f675c6b796e53e810737 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 22 Dec 2021 08:42:33 +0100 Subject: [PATCH 008/136] ASW-375 - Query --- AdyenPayment.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AdyenPayment.php b/AdyenPayment.php index 7e74ed1c..dca53a93 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -209,8 +209,10 @@ private function installStoredPaymentUmbrella(InstallContext $context): void $payment->setDescription('Stored Payment'); $payment->setAdditionalDescription('Adyen Stored Payment'); - $sql = 'SELECT `id` FROM `s_core_paymentmeans` WHERE `name` = "'.self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE.'"'; - $paymentId = $database->fetchRow($sql)['id'] ?? null; + $paymentId = $database->fetchRow( + 'SELECT `id` FROM `s_core_paymentmeans` WHERE `name` = :name', + [':name' => self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE] + )['id'] ?? null; if (null === $paymentId) { $modelsManager->persist($payment); From 904fecb1e5764b2d4906eda8f74c38157ecb0da3 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 22 Dec 2021 11:33:46 +0100 Subject: [PATCH 009/136] ASW-375 - Hide from admin --- Resources/services/subscribers.xml | 4 ++ .../HideStoredPaymentUmbrellaSubscriber.php | 50 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index d18f2cd6..4ff33dd1 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -33,6 +33,10 @@ %adyen_payment.plugin_dir% + + + + diff --git a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php new file mode 100644 index 00000000..224ffeb1 --- /dev/null +++ b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php @@ -0,0 +1,50 @@ + '__invoke', + ]; + } + + public function __invoke(\Enlight_Controller_ActionEventArgs $args): void + { + $request = $args->get('request') ?? false; + $response = $args->get('response') ?? false; + + if (!$request || !$response) { + return; + } + + if ( + Response::HTTP_OK !== $response->getHttpResponseCode() + || self::GET_PAYMENTS_ACTION !== $request->getActionName() + ) { + return; + } + + $assign = $args->getSubject()->View()->getAssign(); + $data = $assign['data'] ?? null; + if (null === $data) { + return; + } + + $filtered = array_values(array_filter($assign['data'], static function($paymentMethod) { + return AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE !== $paymentMethod['name']; + })); + + $args->getSubject()->View()->assign(['success' => true, 'data' => $filtered]); + } +} From bf42f228f1b7959b64f1037fb2fd3adacaaf4719 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 22 Dec 2021 12:27:36 +0100 Subject: [PATCH 010/136] ASW-375 - Unit tests --- .../HideStoredPaymentUmbrellaSubscriber.php | 2 +- ...ideStoredPaymentUmbrellaSubscriberTest.php | 132 ++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php diff --git a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php index 224ffeb1..dfdebba6 100644 --- a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php +++ b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php @@ -37,7 +37,7 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void $assign = $args->getSubject()->View()->getAssign(); $data = $assign['data'] ?? null; - if (null === $data) { + if (!is_array($data)) { return; } diff --git a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php new file mode 100644 index 00000000..bd2bf3e5 --- /dev/null +++ b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php @@ -0,0 +1,132 @@ +args = $this->prophesize(\Enlight_Controller_ActionEventArgs::class); + $this->request = $this->prophesize(\Enlight_Controller_Request_Request::class); + $this->response = $this->prophesize(\Enlight_Controller_Response_Response::class); + + $this->subscriber = new HideStoredPaymentUmbrellaSubscriber(); + } + + /** @test */ + public function it_is_a_subscriber(): void + { + self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); + } + + /** @test */ + public function it_does_nothing_on_missing_request(): void + { + $this->args->get('request')->willReturn(false); + $this->args->get('response')->willReturn($this->response->reveal()); + $this->response->getHttpResponseCode()->shouldNotBeCalled(); + $this->request->getActionName()->shouldNotBeCalled(); + + ($this->subscriber)($this->args->reveal()); + } + + /** @test */ + public function it_does_nothing_on_missing_response(): void + { + $this->args->get('request')->willReturn($this->request->reveal()); + $this->args->get('response')->willReturn(false); + $this->response->getHttpResponseCode()->shouldNotBeCalled(); + $this->request->getActionName()->shouldNotBeCalled(); + + ($this->subscriber)($this->args->reveal()); + } + + /** @test */ + public function it_does_nothing_on_wrong_response_code(): void + { + $this->args->get('request')->willReturn($this->request->reveal()); + $this->args->get('response')->willReturn($this->response->reveal()); + $this->response->getHttpResponseCode()->willReturn('any-code'); + $this->request->getActionName()->shouldNotBeCalled(); + + ($this->subscriber)($this->args->reveal()); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_action_name(): void + { + $this->args->get('request')->willReturn($this->request->reveal()); + $this->args->get('response')->willReturn($this->response->reveal()); + $this->response->getHttpResponseCode()->willReturn(Response::HTTP_OK); + $this->request->getActionName()->willReturn('invalid-action-name'); + $this->args->getSubject()->shouldNotBeCalled(); + + ($this->subscriber)($this->args->reveal()); + } + + /** @test */ + public function it_does_nothing_on_wrong_data(): void + { + $view = $this->prophesize(\Enlight_View_Default::class); + $view->getAssign()->willReturn([]); // $assign['data'] undefined + $subject = $this->prophesize(\Enlight_Controller_Action::class); + $subject->View()->willReturn($view->reveal()); + + $this->args->get('request')->willReturn($this->request->reveal()); + $this->args->get('response')->willReturn($this->response->reveal()); + $this->response->getHttpResponseCode()->willReturn(Response::HTTP_OK); + $this->request->getActionName()->willReturn('getPayments'); + $this->args->getSubject()->willReturn($subject->reveal()); + + ($this->subscriber)($this->args->reveal()); + } + + /** @test */ + public function it_will_filter_from_the_view_the_stored_payment_umbrella(): void + { + $expected = [ + ['name' => 'Payment Method 1'], + ['name' => 'Payment Method 2'], + ]; + $rawMethods = ['data' => array_merge( + [['name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE]], + $expected + )]; + + $view = $this->prophesize(\Enlight_View_Default::class); + $view->getAssign()->willReturn($rawMethods); + $subject = $this->prophesize(\Enlight_Controller_Action::class); + $subject->View()->willReturn($view->reveal()); + + $this->args->get('request')->willReturn($this->request->reveal()); + $this->args->get('response')->willReturn($this->response->reveal()); + $this->response->getHttpResponseCode()->willReturn(Response::HTTP_OK); + $this->request->getActionName()->willReturn('getPayments'); + $this->args->getSubject()->willReturn($subject->reveal()); + $view->assign(['success' => true, 'data' => $expected])->shouldBeCalled(); + + ($this->subscriber)($this->args->reveal()); + } +} From 6faf366cbdabaf550c9a238a4b5c8234cff31679 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 23 Dec 2021 08:53:23 +0100 Subject: [PATCH 011/136] ASW-375 - CR fixes --- AdyenPayment.php | 4 ++-- Resources/services/subscribers.xml | 1 - .../Backend/HideStoredPaymentUmbrellaSubscriber.php | 2 +- .../HideStoredPaymentUmbrellaSubscriberTest.php | 9 +++++++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/AdyenPayment.php b/AdyenPayment.php index dca53a93..cd46af00 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -206,8 +206,8 @@ private function installStoredPaymentUmbrella(InstallContext $context): void $payment->setSource(SourceType::adyen()->getType()); $payment->setHide(true); $payment->setPluginId($context->getPlugin()->getId()); - $payment->setDescription('Stored Payment'); - $payment->setAdditionalDescription('Adyen Stored Payment'); + $payment->setDescription(self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE); + $payment->setAdditionalDescription(self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE); $paymentId = $database->fetchRow( 'SELECT `id` FROM `s_core_paymentmeans` WHERE `name` = :name', diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index 4ff33dd1..cbce25c2 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -35,7 +35,6 @@ - diff --git a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php index dfdebba6..28e20f3d 100644 --- a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php +++ b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php @@ -15,7 +15,7 @@ final class HideStoredPaymentUmbrellaSubscriber implements SubscriberInterface public static function getSubscribedEvents(): array { return [ - 'Enlight_Controller_Action_PostDispatchSecure' => '__invoke', + 'Enlight_Controller_Action_PostDispatch_Backend_Payment' => '__invoke', ]; } diff --git a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php index bd2bf3e5..984e699f 100644 --- a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php +++ b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php @@ -41,6 +41,15 @@ public function it_is_a_subscriber(): void self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); } + /** @test */ + public function it_subscribe_to_the_proper_events(): void + { + self::assertEquals( + ['Enlight_Controller_Action_PostDispatch_Backend_Payment' => '__invoke'], + HideStoredPaymentUmbrellaSubscriber::getSubscribedEvents() + ); + } + /** @test */ public function it_does_nothing_on_missing_request(): void { From 705668c8d7a2b11d373d03c0900d2d208a1712d2 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 23 Dec 2021 10:04:56 +0100 Subject: [PATCH 012/136] ASW-375 - Hide field check --- .../frontend/checkout/change_payment.tpl | 3 ++ .../frontend/register/payment_fieldset.tpl | 47 +++++++++++++++++++ .../HideStoredPaymentUmbrellaSubscriber.php | 7 ++- ...ideStoredPaymentUmbrellaSubscriberTest.php | 2 +- 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 Resources/views/frontend/register/payment_fieldset.tpl diff --git a/Resources/views/frontend/checkout/change_payment.tpl b/Resources/views/frontend/checkout/change_payment.tpl index 85c727eb..9986f51b 100644 --- a/Resources/views/frontend/checkout/change_payment.tpl +++ b/Resources/views/frontend/checkout/change_payment.tpl @@ -7,6 +7,9 @@ {assign var="paymentMethods" value=[]} {assign var="storedPaymentMethods" value=[]} {foreach $sPayments as $paymentMethod} + {if 'hide'|array_key_exists:$paymentMethod && '1' === $paymentMethod.hide} + {continue} + {/if} {if 'isStoredPayment'|array_key_exists:$paymentMethod && true === $paymentMethod.isStoredPayment} {$storedPaymentMethods[] = $paymentMethod} {else} diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl new file mode 100644 index 00000000..79ebd413 --- /dev/null +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -0,0 +1,47 @@ +{extends file="parent:frontend/register/payment_fieldset.tpl"} + +{block name="frontend_register_payment_fieldset"} +
+ {foreach $payment_means as $payment_mean} + {if 'hide'|array_key_exists:$payment_mean && '1' === $payment_mean.hide} + {continue} + {/if} + + {block name="frontend_register_payment_method"} +
+ + {block name="frontend_register_payment_fieldset_input"} +
+ {block name="frontend_register_payment_fieldset_input_radio"} + + {/block} +
+
+ {block name="frontend_register_payment_fieldset_input_label"} + + {/block} +
+ {/block} + + {block name="frontend_register_payment_fieldset_description"} +
+ {include file="string:{$payment_mean.additionaldescription}"} +
+ {/block} + + {block name='frontend_register_payment_fieldset_template'} +
+ {if "frontend/plugins/payment/`$payment_mean.template`"|template_exists} +
+ {include file="frontend/plugins/payment/`$payment_mean.template`" checked = ($payment_mean.id == $form_data.payment)} +
+ {/if} + {/block} +
+ {/block} + + {/foreach} +
+{/block} diff --git a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php index 28e20f3d..af4865e2 100644 --- a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php +++ b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php @@ -35,13 +35,12 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } - $assign = $args->getSubject()->View()->getAssign(); - $data = $assign['data'] ?? null; - if (!is_array($data)) { + $data = $args->getSubject()->View()->getAssign()['data'] ?? []; + if (0 === count($data)) { return; } - $filtered = array_values(array_filter($assign['data'], static function($paymentMethod) { + $filtered = array_values(array_filter($data, static function($paymentMethod) { return AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE !== $paymentMethod['name']; })); diff --git a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php index 984e699f..17e0feac 100644 --- a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php +++ b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php @@ -99,7 +99,7 @@ public function it_does_nothing_on_wrong_request_action_name(): void public function it_does_nothing_on_wrong_data(): void { $view = $this->prophesize(\Enlight_View_Default::class); - $view->getAssign()->willReturn([]); // $assign['data'] undefined + $view->getAssign()->willReturn([]); $subject = $this->prophesize(\Enlight_Controller_Action::class); $subject->View()->willReturn($view->reveal()); From 9e0b8acb8dc0807d0e91c5da18455bcd34870f04 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 23 Dec 2021 10:38:38 +0100 Subject: [PATCH 013/136] ASW-375 - Hide on backend shipping section --- Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php | 1 + .../Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php index af4865e2..c4b69a19 100644 --- a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php +++ b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php @@ -16,6 +16,7 @@ public static function getSubscribedEvents(): array { return [ 'Enlight_Controller_Action_PostDispatch_Backend_Payment' => '__invoke', + 'Enlight_Controller_Action_PostDispatch_Backend_Shipping' => '__invoke', ]; } diff --git a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php index 17e0feac..fa76c43d 100644 --- a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php +++ b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php @@ -45,7 +45,10 @@ public function it_is_a_subscriber(): void public function it_subscribe_to_the_proper_events(): void { self::assertEquals( - ['Enlight_Controller_Action_PostDispatch_Backend_Payment' => '__invoke'], + [ + 'Enlight_Controller_Action_PostDispatch_Backend_Payment' => '__invoke', + 'Enlight_Controller_Action_PostDispatch_Backend_Shipping' => '__invoke', + ], HideStoredPaymentUmbrellaSubscriber::getSubscribedEvents() ); } From ae272a03c1f4a191770855181740745ab89efa45 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 27 Dec 2021 08:41:27 +0100 Subject: [PATCH 014/136] ASW-375 - Secure susbscribers --- Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php | 4 ++-- .../Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php index c4b69a19..3a3b18cc 100644 --- a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php +++ b/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php @@ -15,8 +15,8 @@ final class HideStoredPaymentUmbrellaSubscriber implements SubscriberInterface public static function getSubscribedEvents(): array { return [ - 'Enlight_Controller_Action_PostDispatch_Backend_Payment' => '__invoke', - 'Enlight_Controller_Action_PostDispatch_Backend_Shipping' => '__invoke', + 'Enlight_Controller_Action_PostDispatchSecure_Backend_Payment' => '__invoke', + 'Enlight_Controller_Action_PostDispatchSecure_Backend_Shipping' => '__invoke', ]; } diff --git a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php index fa76c43d..c7523791 100644 --- a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php +++ b/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php @@ -46,8 +46,8 @@ public function it_subscribe_to_the_proper_events(): void { self::assertEquals( [ - 'Enlight_Controller_Action_PostDispatch_Backend_Payment' => '__invoke', - 'Enlight_Controller_Action_PostDispatch_Backend_Shipping' => '__invoke', + 'Enlight_Controller_Action_PostDispatchSecure_Backend_Payment' => '__invoke', + 'Enlight_Controller_Action_PostDispatchSecure_Backend_Shipping' => '__invoke', ], HideStoredPaymentUmbrellaSubscriber::getSubscribedEvents() ); From e4c3c7fc240d99dcfdff53a7240b8aa923f2ef7c Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 27 Dec 2021 09:10:18 +0100 Subject: [PATCH 015/136] ASW-375 - ASW-379 - Hide refactor --- Resources/services/subscribers.xml | 2 +- ...r.php => HideStoredPaymentsSubscriber.php} | 22 ++++++++++++++----- ...p => HideStoredPaymentsSubscriberTest.php} | 18 ++++++++------- 3 files changed, 27 insertions(+), 15 deletions(-) rename Subscriber/Backend/{HideStoredPaymentUmbrellaSubscriber.php => HideStoredPaymentsSubscriber.php} (63%) rename tests/Unit/Subscriber/{HideStoredPaymentUmbrellaSubscriberTest.php => HideStoredPaymentsSubscriberTest.php} (89%) diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index cbce25c2..d419e802 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -33,7 +33,7 @@ %adyen_payment.plugin_dir% - + diff --git a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php b/Subscriber/Backend/HideStoredPaymentsSubscriber.php similarity index 63% rename from Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php rename to Subscriber/Backend/HideStoredPaymentsSubscriber.php index 3a3b18cc..f03196d0 100644 --- a/Subscriber/Backend/HideStoredPaymentUmbrellaSubscriber.php +++ b/Subscriber/Backend/HideStoredPaymentsSubscriber.php @@ -4,11 +4,11 @@ namespace AdyenPayment\Subscriber\Backend; -use AdyenPayment\AdyenPayment; +use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use Enlight\Event\SubscriberInterface; use Symfony\Component\HttpFoundation\Response; -final class HideStoredPaymentUmbrellaSubscriber implements SubscriberInterface +final class HideStoredPaymentsSubscriber implements SubscriberInterface { private const GET_PAYMENTS_ACTION = 'getPayments'; @@ -41,10 +41,20 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } - $filtered = array_values(array_filter($data, static function($paymentMethod) { - return AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE !== $paymentMethod['name']; - })); + $adyenSourceType = SourceType::adyen(); + foreach ($data as $key => $paymentMethod) { + if (false === (bool) ($paymentMethod['hide'] ?? false)) { + continue; + } - $args->getSubject()->View()->assign(['success' => true, 'data' => $filtered]); + $sourceType = SourceType::load($paymentMethod['source'] ?? null); + if (!$sourceType->equals($adyenSourceType)) { + continue; + } + + unset($data[$key]); + } + + $args->getSubject()->View()->assign('data', array_values($data)); } } diff --git a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php b/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php similarity index 89% rename from tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php rename to tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php index c7523791..343955da 100644 --- a/tests/Unit/Subscriber/HideStoredPaymentUmbrellaSubscriberTest.php +++ b/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php @@ -4,18 +4,19 @@ namespace AdyenPayment\Tests\Unit\Shopware\Plugin; -use AdyenPayment\AdyenPayment; -use AdyenPayment\Subscriber\Backend\HideStoredPaymentUmbrellaSubscriber; +use AdyenPayment\Models\Enum\PaymentMethod\SourceType; +use AdyenPayment\Subscriber\Backend\HideStoredPaymentsSubscriber; use Enlight\Event\SubscriberInterface; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; use Symfony\Component\HttpFoundation\Response; -final class HideStoredPaymentUmbrellaSubscriberTest extends TestCase +final class HideStoredPaymentsSubscriberTest extends TestCase { use ProphecyTrait; - private HideStoredPaymentUmbrellaSubscriber $subscriber; + private HideStoredPaymentsSubscriber $subscriber; /** @var \Enlight_Controller_ActionEventArgs|ObjectProphecy */ private $args; @@ -32,7 +33,7 @@ protected function setUp(): void $this->request = $this->prophesize(\Enlight_Controller_Request_Request::class); $this->response = $this->prophesize(\Enlight_Controller_Response_Response::class); - $this->subscriber = new HideStoredPaymentUmbrellaSubscriber(); + $this->subscriber = new HideStoredPaymentsSubscriber(); } /** @test */ @@ -49,7 +50,7 @@ public function it_subscribe_to_the_proper_events(): void 'Enlight_Controller_Action_PostDispatchSecure_Backend_Payment' => '__invoke', 'Enlight_Controller_Action_PostDispatchSecure_Backend_Shipping' => '__invoke', ], - HideStoredPaymentUmbrellaSubscriber::getSubscribedEvents() + HideStoredPaymentsSubscriber::getSubscribedEvents() ); } @@ -111,6 +112,7 @@ public function it_does_nothing_on_wrong_data(): void $this->response->getHttpResponseCode()->willReturn(Response::HTTP_OK); $this->request->getActionName()->willReturn('getPayments'); $this->args->getSubject()->willReturn($subject->reveal()); + $view->assign(Argument::cetera())->shouldNotBeCalled(); ($this->subscriber)($this->args->reveal()); } @@ -123,7 +125,7 @@ public function it_will_filter_from_the_view_the_stored_payment_umbrella(): void ['name' => 'Payment Method 2'], ]; $rawMethods = ['data' => array_merge( - [['name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE]], + [['hide' => 1, 'source' => SourceType::adyen()->getType()]], $expected )]; @@ -137,7 +139,7 @@ public function it_will_filter_from_the_view_the_stored_payment_umbrella(): void $this->response->getHttpResponseCode()->willReturn(Response::HTTP_OK); $this->request->getActionName()->willReturn('getPayments'); $this->args->getSubject()->willReturn($subject->reveal()); - $view->assign(['success' => true, 'data' => $expected])->shouldBeCalled(); + $view->assign('data', $expected)->shouldBeCalled(); ($this->subscriber)($this->args->reveal()); } From 4c2bdb1727fd8e5cdce7991bde74422a6d3275a3 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 4 Jan 2022 08:03:03 +0100 Subject: [PATCH 016/136] ASW-375 - CR fixes --- Subscriber/Backend/HideStoredPaymentsSubscriber.php | 13 +++++++------ .../Subscriber/HideStoredPaymentsSubscriberTest.php | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Subscriber/Backend/HideStoredPaymentsSubscriber.php b/Subscriber/Backend/HideStoredPaymentsSubscriber.php index f03196d0..07349c14 100644 --- a/Subscriber/Backend/HideStoredPaymentsSubscriber.php +++ b/Subscriber/Backend/HideStoredPaymentsSubscriber.php @@ -42,19 +42,20 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void } $adyenSourceType = SourceType::adyen(); - foreach ($data as $key => $paymentMethod) { + + $data = array_values(array_filter($data, static function($paymentMethod) use ($adyenSourceType) { if (false === (bool) ($paymentMethod['hide'] ?? false)) { - continue; + return true; } $sourceType = SourceType::load($paymentMethod['source'] ?? null); if (!$sourceType->equals($adyenSourceType)) { - continue; + return true; } - unset($data[$key]); - } + return false; + })); - $args->getSubject()->View()->assign('data', array_values($data)); + $args->getSubject()->View()->assign('data', $data); } } diff --git a/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php b/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php index 343955da..d7c83539 100644 --- a/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php +++ b/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php @@ -59,6 +59,7 @@ public function it_does_nothing_on_missing_request(): void { $this->args->get('request')->willReturn(false); $this->args->get('response')->willReturn($this->response->reveal()); + $this->args->getSubject()->shouldNotBeCalled(); $this->response->getHttpResponseCode()->shouldNotBeCalled(); $this->request->getActionName()->shouldNotBeCalled(); @@ -70,6 +71,7 @@ public function it_does_nothing_on_missing_response(): void { $this->args->get('request')->willReturn($this->request->reveal()); $this->args->get('response')->willReturn(false); + $this->args->getSubject()->shouldNotBeCalled(); $this->response->getHttpResponseCode()->shouldNotBeCalled(); $this->request->getActionName()->shouldNotBeCalled(); @@ -81,6 +83,7 @@ public function it_does_nothing_on_wrong_response_code(): void { $this->args->get('request')->willReturn($this->request->reveal()); $this->args->get('response')->willReturn($this->response->reveal()); + $this->args->getSubject()->shouldNotBeCalled(); $this->response->getHttpResponseCode()->willReturn('any-code'); $this->request->getActionName()->shouldNotBeCalled(); From 888d6bb1d3169db200118d61d8b017af3389f324 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 4 Jan 2022 09:44:30 +0100 Subject: [PATCH 017/136] ASW-375 - CR fixes --- .../EnrichedPaymentMeanProvider.php | 4 ++ .../frontend/checkout/change_payment.tpl | 3 -- .../frontend/register/payment_fieldset.tpl | 47 ------------------- 3 files changed, 4 insertions(+), 50 deletions(-) delete mode 100644 Resources/views/frontend/register/payment_fieldset.tpl diff --git a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php index d400b4b5..9bdbf0b4 100644 --- a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php @@ -49,6 +49,10 @@ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollec return new PaymentMeanCollection(...$paymentMeans->map( static function(PaymentMean $shopwareMethod) use ($adyenPaymentMethods, $enricher): ?PaymentMean { + $hiddenPayment = (bool) $shopwareMethod->getValue('hide'); + if ($hiddenPayment) { + return null; + } if (!$shopwareMethod->getSource()->equals(SourceType::adyen())) { return $shopwareMethod; } diff --git a/Resources/views/frontend/checkout/change_payment.tpl b/Resources/views/frontend/checkout/change_payment.tpl index 9986f51b..85c727eb 100644 --- a/Resources/views/frontend/checkout/change_payment.tpl +++ b/Resources/views/frontend/checkout/change_payment.tpl @@ -7,9 +7,6 @@ {assign var="paymentMethods" value=[]} {assign var="storedPaymentMethods" value=[]} {foreach $sPayments as $paymentMethod} - {if 'hide'|array_key_exists:$paymentMethod && '1' === $paymentMethod.hide} - {continue} - {/if} {if 'isStoredPayment'|array_key_exists:$paymentMethod && true === $paymentMethod.isStoredPayment} {$storedPaymentMethods[] = $paymentMethod} {else} diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl deleted file mode 100644 index 79ebd413..00000000 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ /dev/null @@ -1,47 +0,0 @@ -{extends file="parent:frontend/register/payment_fieldset.tpl"} - -{block name="frontend_register_payment_fieldset"} -
- {foreach $payment_means as $payment_mean} - {if 'hide'|array_key_exists:$payment_mean && '1' === $payment_mean.hide} - {continue} - {/if} - - {block name="frontend_register_payment_method"} -
- - {block name="frontend_register_payment_fieldset_input"} -
- {block name="frontend_register_payment_fieldset_input_radio"} - - {/block} -
-
- {block name="frontend_register_payment_fieldset_input_label"} - - {/block} -
- {/block} - - {block name="frontend_register_payment_fieldset_description"} -
- {include file="string:{$payment_mean.additionaldescription}"} -
- {/block} - - {block name='frontend_register_payment_fieldset_template'} -
- {if "frontend/plugins/payment/`$payment_mean.template`"|template_exists} -
- {include file="frontend/plugins/payment/`$payment_mean.template`" checked = ($payment_mean.id == $form_data.payment)} -
- {/if} - {/block} -
- {/block} - - {/foreach} -
-{/block} From 75395728f29361496c653972b9cb861a3d795bd0 Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Tue, 4 Jan 2022 14:12:13 +0100 Subject: [PATCH 018/136] ASW-375 refactor code --- Collection/Payment/PaymentMeanCollection.php | 38 +++++++++---------- .../Payment/PaymentMethodCollection.php | 2 +- .../EnrichedPaymentMeanProvider.php | 38 ++++++------------- Models/Payment/PaymentMean.php | 5 +++ .../EnrichedPaymentMeanProviderTest.php | 9 ++--- tests/Unit/Models/Payment/PaymentMeanTest.php | 8 ++++ 6 files changed, 48 insertions(+), 52 deletions(-) diff --git a/Collection/Payment/PaymentMeanCollection.php b/Collection/Payment/PaymentMeanCollection.php index ea797942..aaeae418 100644 --- a/Collection/Payment/PaymentMeanCollection.php +++ b/Collection/Payment/PaymentMeanCollection.php @@ -6,10 +6,8 @@ use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMean; -use Countable; -use IteratorAggregate; -final class PaymentMeanCollection implements IteratorAggregate, Countable +final class PaymentMeanCollection implements \IteratorAggregate, \Countable { /** * @var array @@ -23,12 +21,10 @@ public function __construct(PaymentMean ...$paymentMeans) public static function createFromShopwareArray(array $paymentMeans): self { - return new self( - ...array_map( - static fn(array $paymentMean) => PaymentMean::createFromShopwareArray($paymentMean), - $paymentMeans - ) - ); + return new self(...array_map( + static fn(array $paymentMean): PaymentMean => PaymentMean::createFromShopwareArray($paymentMean), + $paymentMeans + )); } /** @@ -57,7 +53,7 @@ public function filter(callable $filter): self public function filterBySource(SourceType $source): self { return $this->filter( - static function(PaymentMean $paymentMean) use ($source) { + static function(PaymentMean $paymentMean) use ($source): bool { return $source->equals($paymentMean->getSource()); } ); @@ -66,12 +62,20 @@ static function(PaymentMean $paymentMean) use ($source) { public function filterExcludeAdyen(): self { return $this->filter( - static function(PaymentMean $paymentMean) { + static function(PaymentMean $paymentMean): bool { return !$paymentMean->getSource()->equals(SourceType::adyen()); } ); } + public function filterExcludeHidden(): self + { + return new self(...array_filter( + $this->paymentMeans, + static fn(PaymentMean $paymentMean): bool => !$paymentMean->isHidden() + )); + } + public function filterByAdyenSource(): self { return $this->filterBySource(SourceType::adyen()); @@ -79,14 +83,10 @@ public function filterByAdyenSource(): self public function toShopwareArray(): array { - return array_reduce( - $this->paymentMeans, - static function(array $payload, PaymentMean $paymentMean) { - $payload[$paymentMean->getId()] = $paymentMean->getRaw(); + return array_reduce($this->paymentMeans, static function(array $payload, PaymentMean $paymentMean): array { + $payload[$paymentMean->getId()] = $paymentMean->getRaw(); - return $payload; - }, - [] - ); + return $payload; + }, []); } } diff --git a/Collection/Payment/PaymentMethodCollection.php b/Collection/Payment/PaymentMethodCollection.php index c71fe9b1..110d3a15 100644 --- a/Collection/Payment/PaymentMethodCollection.php +++ b/Collection/Payment/PaymentMethodCollection.php @@ -83,7 +83,7 @@ public function mapToRaw(): array * $identifierOrStoredId is the Adyen "unique identifier" or Adyen "stored payment id" * NOT the Shopware id. */ - public function fetchByIdentifierOrStoredId(string $identifierOrStoredId): ?PaymentMethod + private function fetchByIdentifierOrStoredId(string $identifierOrStoredId): ?PaymentMethod { foreach ($this->paymentMethods as $paymentMethod) { if ($paymentMethod->getStoredPaymentMethodId() === $identifierOrStoredId) { diff --git a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php index 9bdbf0b4..8d327415 100644 --- a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php @@ -4,14 +4,12 @@ namespace AdyenPayment\Components\Adyen\PaymentMethod; -use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Components\Adyen\Builder\PaymentMethodOptionsBuilderInterface; use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use AdyenPayment\Enricher\Payment\PaymentMethodEnricherInterface; use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMean; -use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; final class EnrichedPaymentMeanProvider implements EnrichedPaymentMeanProviderInterface { @@ -29,9 +27,6 @@ public function __construct( $this->paymentMethodEnricher = $paymentMethodEnricher; } - /** - * @throws \Adyen\AdyenException - */ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollection { $paymentMethodOptions = ($this->paymentMethodOptionsBuilder)(); @@ -47,33 +42,22 @@ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollec $enricher = $this->paymentMethodEnricher; - return new PaymentMeanCollection(...$paymentMeans->map( - static function(PaymentMean $shopwareMethod) use ($adyenPaymentMethods, $enricher): ?PaymentMean { - $hiddenPayment = (bool) $shopwareMethod->getValue('hide'); - if ($hiddenPayment) { - return null; - } - if (!$shopwareMethod->getSource()->equals(SourceType::adyen())) { - return $shopwareMethod; - } - - /** @var Attribute $attribute */ - $attribute = $shopwareMethod->getValue('attribute'); - if (!$attribute) { - return $shopwareMethod; + return new PaymentMeanCollection(...$paymentMeans + ->filterExcludeHidden() + ->map(static function(PaymentMean $paymentMean) use ($adyenPaymentMethods, $enricher): ?PaymentMean { + if (!$paymentMean->getSource()->equals(SourceType::adyen())) { + return $paymentMean; } - $identifierOrStoredId = (string) ('' !== (string) $attribute->get(AdyenPayment::ADYEN_STORED_METHOD_ID) - ? $attribute->get(AdyenPayment::ADYEN_STORED_METHOD_ID) - : $attribute->get(AdyenPayment::ADYEN_CODE)); - - $paymentMethod = $adyenPaymentMethods->fetchByIdentifierOrStoredId($identifierOrStoredId); + $paymentMethod = $adyenPaymentMethods->fetchByPaymentMean($paymentMean); if (null === $paymentMethod) { return null; } - return PaymentMean::createFromShopwareArray(($enricher)($shopwareMethod->getRaw(), $paymentMethod)); - } - )); + return PaymentMean::createFromShopwareArray( + ($enricher)($paymentMean->getRaw(), $paymentMethod) + ); + }) + ); } } diff --git a/Models/Payment/PaymentMean.php b/Models/Payment/PaymentMean.php index f522fb7e..5cc2ed78 100644 --- a/Models/Payment/PaymentMean.php +++ b/Models/Payment/PaymentMean.php @@ -38,6 +38,11 @@ public function getSource(): SourceType return $this->source; } + public function isHidden(): bool + { + return (bool) ($this->raw['hide'] ?? false); + } + public function getAttribute(): Attribute { return $this->raw['attribute'] ?? new Attribute(); diff --git a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php index a83d9f2d..ba4e6dc8 100644 --- a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php +++ b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php @@ -122,11 +122,11 @@ public function it_does_not_enrich_non_adyen_methods(): void public function it_does_not_enrich_payment_means_without_attribute(): void { $paymentMeans = new PaymentMeanCollection( - $paymentMean = PaymentMean::createFromShopwareArray([ + $paymentMeanOne = PaymentMean::createFromShopwareArray([ 'id' => 19, 'source' => SourceType::shopwareDefault()->getType(), ]), - $paymentMean = PaymentMean::createFromShopwareArray([ + $paymentMeanTwo = PaymentMean::createFromShopwareArray([ 'id' => 21, 'source' => SourceType::adyen()->getType(), ]), @@ -143,9 +143,8 @@ public function it_does_not_enrich_payment_means_without_attribute(): void $result = $this->provider->__invoke($paymentMeans); $this->assertInstanceOf(PaymentMeanCollection::class, $result); - $this->assertCount(2, $result); - $this->assertNotSame($paymentMeans, $result); - $this->assertEquals($paymentMeans, $result); + $this->assertCount(1, $result); + $this->assertEquals(new PaymentMeanCollection($paymentMeanOne), $result); } /** @test */ diff --git a/tests/Unit/Models/Payment/PaymentMeanTest.php b/tests/Unit/Models/Payment/PaymentMeanTest.php index 4d9ee955..322282bb 100644 --- a/tests/Unit/Models/Payment/PaymentMeanTest.php +++ b/tests/Unit/Models/Payment/PaymentMeanTest.php @@ -25,6 +25,7 @@ protected function setUp(): void ]), 'enriched' => true, 'adyenType' => 'adyen-type', + 'hide' => true, ]); } @@ -42,6 +43,12 @@ public function it_contains_a_source(): void $this->assertEquals(SourceType::adyen(), $this->paymentMean->getSource()); } + /** @test */ + public function it_knows_it_is_hidden(): void + { + $this->assertTrue($this->paymentMean->isHidden()); + } + /** @test */ public function it_contains_raw_data(): void { @@ -55,6 +62,7 @@ public function it_contains_raw_data(): void ]), 'enriched' => true, 'adyenType' => 'adyen-type', + 'hide' => true, ], $this->paymentMean->getRaw()); } From 7e3f5519cfb1c0adc3abceae37ed606440fc59dc Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Tue, 4 Jan 2022 14:15:19 +0100 Subject: [PATCH 019/136] ASW-375 rename test case --- .../Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php index ba4e6dc8..9a6c69a4 100644 --- a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php +++ b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php @@ -119,7 +119,7 @@ public function it_does_not_enrich_non_adyen_methods(): void } /** @test */ - public function it_does_not_enrich_payment_means_without_attribute(): void + public function it_does_not_enrich_and_removes_payment_means_without_attribute(): void { $paymentMeans = new PaymentMeanCollection( $paymentMeanOne = PaymentMean::createFromShopwareArray([ From f3a2a6c88dd8963600a8bc8da3d9552fd76dd1a6 Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Tue, 4 Jan 2022 14:17:06 +0100 Subject: [PATCH 020/136] ASW-375 cs flavour --- .../Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php index 9a6c69a4..40f2a3fc 100644 --- a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php +++ b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php @@ -144,7 +144,7 @@ public function it_does_not_enrich_and_removes_payment_means_without_attribute() $result = $this->provider->__invoke($paymentMeans); $this->assertInstanceOf(PaymentMeanCollection::class, $result); $this->assertCount(1, $result); - $this->assertEquals(new PaymentMeanCollection($paymentMeanOne), $result); + $this->assertEquals($paymentMeanOne, iterator_to_array($result)[0]); } /** @test */ From 0f685df099a08e4b77ba0c0709a7c160d0130afe Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Tue, 4 Jan 2022 16:59:06 +0100 Subject: [PATCH 021/136] ASW-375 cleanup code, fix test: use real implementation over mocks --- .../Backend/HideStoredPaymentsSubscriber.php | 42 ++--- tests/Unit/Mock/ControllerActionMock.php | 9 ++ .../HideStoredPaymentsSubscriberTest.php | 119 ++++++++++++++ .../HideStoredPaymentsSubscriberTest.php | 149 ------------------ tests/Unit/Subscriber/SubscriberTestCase.php | 36 +++++ 5 files changed, 181 insertions(+), 174 deletions(-) create mode 100644 tests/Unit/Mock/ControllerActionMock.php create mode 100644 tests/Unit/Subscriber/Backend/HideStoredPaymentsSubscriberTest.php delete mode 100644 tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php create mode 100644 tests/Unit/Subscriber/SubscriberTestCase.php diff --git a/Subscriber/Backend/HideStoredPaymentsSubscriber.php b/Subscriber/Backend/HideStoredPaymentsSubscriber.php index 07349c14..9459e779 100644 --- a/Subscriber/Backend/HideStoredPaymentsSubscriber.php +++ b/Subscriber/Backend/HideStoredPaymentsSubscriber.php @@ -4,7 +4,7 @@ namespace AdyenPayment\Subscriber\Backend; -use AdyenPayment\Models\Enum\PaymentMethod\SourceType; +use AdyenPayment\Collection\Payment\PaymentMeanCollection; use Enlight\Event\SubscriberInterface; use Symfony\Component\HttpFoundation\Response; @@ -22,40 +22,32 @@ public static function getSubscribedEvents(): array public function __invoke(\Enlight_Controller_ActionEventArgs $args): void { - $request = $args->get('request') ?? false; - $response = $args->get('response') ?? false; - - if (!$request || !$response) { + if (!$this->isSuccessGetPaymentAction($args)) { return; } - if ( - Response::HTTP_OK !== $response->getHttpResponseCode() - || self::GET_PAYMENTS_ACTION !== $request->getActionName() - ) { + $data = $args->getSubject()->View()->getAssign('data') ?? []; + if (!count($data)) { return; } - $data = $args->getSubject()->View()->getAssign()['data'] ?? []; - if (0 === count($data)) { - return; - } + $data = PaymentMeanCollection::createFromShopwareArray($data) + ->filterExcludeHidden() + ->toShopwareArray(); - $adyenSourceType = SourceType::adyen(); - - $data = array_values(array_filter($data, static function($paymentMethod) use ($adyenSourceType) { - if (false === (bool) ($paymentMethod['hide'] ?? false)) { - return true; - } + $args->getSubject()->View()->assign('data', array_values($data)); + } - $sourceType = SourceType::load($paymentMethod['source'] ?? null); - if (!$sourceType->equals($adyenSourceType)) { - return true; - } + private function isSuccessGetPaymentAction(\Enlight_Controller_ActionEventArgs $args): bool + { + if (!$args->getResponse() || Response::HTTP_OK !== $args->getResponse()->getHttpResponseCode()) { + return false; + } + if (!$args->getRequest() || self::GET_PAYMENTS_ACTION !== $args->getRequest()->getActionName()) { return false; - })); + } - $args->getSubject()->View()->assign('data', $data); + return true; } } diff --git a/tests/Unit/Mock/ControllerActionMock.php b/tests/Unit/Mock/ControllerActionMock.php new file mode 100644 index 00000000..d32ff66f --- /dev/null +++ b/tests/Unit/Mock/ControllerActionMock.php @@ -0,0 +1,9 @@ +subscriber = new HideStoredPaymentsSubscriber(); + } + + /** @test */ + public function it_is_a_subscriber(): void + { + self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); + } + + /** @test */ + public function it_subscribe_to_the_proper_events(): void + { + self::assertEquals( + [ + 'Enlight_Controller_Action_PostDispatchSecure_Backend_Payment' => '__invoke', + 'Enlight_Controller_Action_PostDispatchSecure_Backend_Shipping' => '__invoke', + ], + HideStoredPaymentsSubscriber::getSubscribedEvents() + ); + } + + /** @test */ + public function it_does_nothing_on_missing_request(): void + { + $eventArgs = new \Enlight_Controller_ActionEventArgs([ + 'subject' => $this->buildSubject($viewData = ['data' => 'view-data']), + 'request' => null, + 'response' => new \Enlight_Controller_Response_ResponseTestCase(), + ]); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_missing_response(): void + { + $eventArgs = new \Enlight_Controller_ActionEventArgs([ + 'subject' => $this->buildSubject($viewData = ['data' => 'view-data']), + 'request' => new \Enlight_Controller_Request_RequestTestCase(), + 'response' => null, + ]); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_non_success_response_code(): void + { + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data'], Response::HTTP_BAD_REQUEST); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_action_name(): void + { + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_empty_view_data(): void + { + $eventArgs = $this->buildEventArgs('getPayments', $viewData = []); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_filters_hidden_payment_means(): void + { + $viewData = [ + 'data' => [ + $nonHiddenPaymentMean = [ + 'name' => 'A payment mean not hidden', + 'source' => SourceType::shopwareDefault()->getType(), + 'hide' => false, + ], + [ + 'name' => 'A hidden payment mean', + 'source' => SourceType::shopwareDefault()->getType(), + 'hide' => true, + ], + ], + ]; + $eventArgs = $this->buildEventArgs('getPayments', $viewData); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals([ + 'data' => [ + $nonHiddenPaymentMean, + ], + ], $eventArgs->getSubject()->View()->getAssign()); + } +} diff --git a/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php b/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php deleted file mode 100644 index d7c83539..00000000 --- a/tests/Unit/Subscriber/HideStoredPaymentsSubscriberTest.php +++ /dev/null @@ -1,149 +0,0 @@ -args = $this->prophesize(\Enlight_Controller_ActionEventArgs::class); - $this->request = $this->prophesize(\Enlight_Controller_Request_Request::class); - $this->response = $this->prophesize(\Enlight_Controller_Response_Response::class); - - $this->subscriber = new HideStoredPaymentsSubscriber(); - } - - /** @test */ - public function it_is_a_subscriber(): void - { - self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); - } - - /** @test */ - public function it_subscribe_to_the_proper_events(): void - { - self::assertEquals( - [ - 'Enlight_Controller_Action_PostDispatchSecure_Backend_Payment' => '__invoke', - 'Enlight_Controller_Action_PostDispatchSecure_Backend_Shipping' => '__invoke', - ], - HideStoredPaymentsSubscriber::getSubscribedEvents() - ); - } - - /** @test */ - public function it_does_nothing_on_missing_request(): void - { - $this->args->get('request')->willReturn(false); - $this->args->get('response')->willReturn($this->response->reveal()); - $this->args->getSubject()->shouldNotBeCalled(); - $this->response->getHttpResponseCode()->shouldNotBeCalled(); - $this->request->getActionName()->shouldNotBeCalled(); - - ($this->subscriber)($this->args->reveal()); - } - - /** @test */ - public function it_does_nothing_on_missing_response(): void - { - $this->args->get('request')->willReturn($this->request->reveal()); - $this->args->get('response')->willReturn(false); - $this->args->getSubject()->shouldNotBeCalled(); - $this->response->getHttpResponseCode()->shouldNotBeCalled(); - $this->request->getActionName()->shouldNotBeCalled(); - - ($this->subscriber)($this->args->reveal()); - } - - /** @test */ - public function it_does_nothing_on_wrong_response_code(): void - { - $this->args->get('request')->willReturn($this->request->reveal()); - $this->args->get('response')->willReturn($this->response->reveal()); - $this->args->getSubject()->shouldNotBeCalled(); - $this->response->getHttpResponseCode()->willReturn('any-code'); - $this->request->getActionName()->shouldNotBeCalled(); - - ($this->subscriber)($this->args->reveal()); - } - - /** @test */ - public function it_does_nothing_on_wrong_request_action_name(): void - { - $this->args->get('request')->willReturn($this->request->reveal()); - $this->args->get('response')->willReturn($this->response->reveal()); - $this->response->getHttpResponseCode()->willReturn(Response::HTTP_OK); - $this->request->getActionName()->willReturn('invalid-action-name'); - $this->args->getSubject()->shouldNotBeCalled(); - - ($this->subscriber)($this->args->reveal()); - } - - /** @test */ - public function it_does_nothing_on_wrong_data(): void - { - $view = $this->prophesize(\Enlight_View_Default::class); - $view->getAssign()->willReturn([]); - $subject = $this->prophesize(\Enlight_Controller_Action::class); - $subject->View()->willReturn($view->reveal()); - - $this->args->get('request')->willReturn($this->request->reveal()); - $this->args->get('response')->willReturn($this->response->reveal()); - $this->response->getHttpResponseCode()->willReturn(Response::HTTP_OK); - $this->request->getActionName()->willReturn('getPayments'); - $this->args->getSubject()->willReturn($subject->reveal()); - $view->assign(Argument::cetera())->shouldNotBeCalled(); - - ($this->subscriber)($this->args->reveal()); - } - - /** @test */ - public function it_will_filter_from_the_view_the_stored_payment_umbrella(): void - { - $expected = [ - ['name' => 'Payment Method 1'], - ['name' => 'Payment Method 2'], - ]; - $rawMethods = ['data' => array_merge( - [['hide' => 1, 'source' => SourceType::adyen()->getType()]], - $expected - )]; - - $view = $this->prophesize(\Enlight_View_Default::class); - $view->getAssign()->willReturn($rawMethods); - $subject = $this->prophesize(\Enlight_Controller_Action::class); - $subject->View()->willReturn($view->reveal()); - - $this->args->get('request')->willReturn($this->request->reveal()); - $this->args->get('response')->willReturn($this->response->reveal()); - $this->response->getHttpResponseCode()->willReturn(Response::HTTP_OK); - $this->request->getActionName()->willReturn('getPayments'); - $this->args->getSubject()->willReturn($subject->reveal()); - $view->assign('data', $expected)->shouldBeCalled(); - - ($this->subscriber)($this->args->reveal()); - } -} diff --git a/tests/Unit/Subscriber/SubscriberTestCase.php b/tests/Unit/Subscriber/SubscriberTestCase.php new file mode 100644 index 00000000..e31863b3 --- /dev/null +++ b/tests/Unit/Subscriber/SubscriberTestCase.php @@ -0,0 +1,36 @@ + $this->buildSubject($viewData), + 'request' => (new \Enlight_Controller_Request_RequestTestCase())->setActionName($actionName), + 'response' => new \Enlight_Controller_Response_ResponseTestCase('', $status), + ]); + } + + protected function buildSubject(array $viewData): \Enlight_Controller_Action + { + Assert::allString(array_keys($viewData)); + + $subject = new ControllerActionMock(); + $subject->setView(new \Enlight_View_Default(new \Enlight_Template_Manager())); + $subject->View()->assign($viewData); + + return $subject; + } +} From 91ed96eb45bab72bc10ff89901ffa2f2cf9aeb34 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 4 Jan 2022 12:44:36 +0100 Subject: [PATCH 022/136] ASW-376 - Unit tests --- .../Payment/PaymentMethodCollectionTest.php | 185 +++++++++++++++++- 1 file changed, 180 insertions(+), 5 deletions(-) diff --git a/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php index de3fdf91..b046f771 100644 --- a/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php +++ b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php @@ -4,12 +4,123 @@ namespace AdyenPayment\Tests\Unit\Collection\Payment; +use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMethodCollection; +use AdyenPayment\Models\Payment\PaymentMean; use AdyenPayment\Models\Payment\PaymentMethod; +use AdyenPayment\Utils\Sanitize; use PHPUnit\Framework\TestCase; +use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; final class PaymentMethodCollectionTest extends TestCase { + /** @test */ + public function it_implements_countable(): void + { + self::assertInstanceOf(\Countable::class, new PaymentMethodCollection()); + } + + /** @test */ + public function it_implements_iterable(): void + { + self::assertInstanceOf(\IteratorAggregate::class, new PaymentMethodCollection()); + } + + /** @test */ + public function it_can_return_an_iterator(): void + { + $result = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [['type' => 'someType']]]); + + self::assertInstanceOf(\Traversable::class, $result->getIterator()); + } + + /** @test */ + public function it_can_count_the_payment_methods(): void + { + $result = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [['type' => 'someType']]]); + + self::assertEquals(1, $result->count()); + } + + /** @test */ + public function it_can_map_with_a_callback(): void + { + $expectedMethod = [true, false]; + $collection = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [ + ['type' => $filteredType = 'someType'], + ['type' => 'otherType'], + ]]); + + $result = $collection->map(static function(PaymentMethod $payment) use ($filteredType) { + return $filteredType === $payment->adyenType()->type(); + }); + + self::assertEquals($expectedMethod, $result); + } + + /** @test */ + public function it_cam_map_to_raw(): void + { + $expected = [ + ['type' => 'someType'], + ['type' => 'otherType'], + ]; + $collection = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => $expected]); + + $result = $collection->mapToRaw(); + + self::assertEquals($expected, $result); + } + + /** @test */ + public function it_can_fetch_by_identifier(): void + { + $paymentMethod = PaymentMethod::fromRaw($paymentMethodData = [ + 'type' => $type = 'someType', + 'name' => $name = 'someName', + ]); + $expectedMethod = $paymentMethod->withCode($name); + $paymentMethodsCollection = PaymentMethodCollection::fromAdyenMethods([ + 'paymentMethods' => [ + $paymentMethodData, + ['type' => 'anotherPaymentMethods'], + ], + ]); + $expectedCode = mb_strtolower(sprintf('%s_%s', $type, Sanitize::removeNonWord($name))); + $collectionWithCodes = $paymentMethodsCollection->withImportLocale($paymentMethodsCollection); + + $result = $collectionWithCodes->fetchByIdentifierOrStoredId($expectedCode); + + self::assertEquals($expectedMethod, $result); + } + + /** @test */ + public function it_can_fetch_by_stored_id(): void + { + $expectedPayment = PaymentMethod::fromRaw($methodData = [ + 'type' => 'someType2', + 'id' => $methodStoredId = 'methodWithId', + ]); + $collection = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [ + ['type' => 'someType'], + $methodData, + ]]); + + $result = $collection->fetchByIdentifierOrStoredId($methodStoredId); + + self::assertEquals($expectedPayment, $result); + } + + /** @test */ + public function it_will_return_null_if_method_not_found_by_identifier_or_stored_id(): void + { + $collection = new PaymentMethodCollection(); + + $result = $collection->fetchByIdentifierOrStoredId('missing-method'); + + self::assertNull($result); + } + /** @test */ public function it_can_map_adyen_payment_methods(): void { @@ -31,14 +142,78 @@ public function it_can_map_adyen_stored_payment_methods(): void } /** @test */ - public function it_can_map_adyen_stored_and_non_stored_payment_methods(): void + public function it_can_map_import_locale(): void { - $result = PaymentMethodCollection::fromAdyenMethods([ - 'storedPaymentMethods' => [['id' => '1234']], - 'paymentMethods' => [['type' => 'someType']], + $paymentMethod = PaymentMethod::fromRaw($paymentMethodData = [ + 'type' => 'someType', + 'name' => $name = 'someName', ]); + $expectedMethod = $paymentMethod->withCode($name); + $paymentMethodsCollection = PaymentMethodCollection::fromAdyenMethods([ + 'paymentMethods' => [$paymentMethodData], + ]); + + $result = $paymentMethodsCollection->withImportLocale($paymentMethodsCollection); self::assertInstanceOf(PaymentMethodCollection::class, $result); - self::assertEquals(2, $result->count()); + self::assertEquals($expectedMethod, $result->getIterator()->current()); + } + + /** @test */ + public function it_will_return_null_on_missing_methods_for_fetch_by_payment_mean(): void + { + $paymentMean = PaymentMean::createFromShopwareArray([ + 'id' => 1, + 'source' => 1425514, + ]); + $collection = new PaymentMethodCollection(); + + $result = $collection->fetchByPaymentMean($paymentMean); + + self::assertNull($result); + } + + /** @test */ + public function it_can_fetch_a_method_by_payment_mean(): void + { + $attribute = new Attribute(); + $attribute->set(AdyenPayment::ADYEN_CODE, 'my_adyen_code'); + $attribute->set(AdyenPayment::ADYEN_STORED_METHOD_ID, $methodStoredId = 1); + $paymentMean = PaymentMean::createFromShopwareArray([ + 'id' => $methodStoredId, + 'source' => 1425514, + 'attribute' => $attribute, + ]); + $expectedPayment = PaymentMethod::fromRaw($methodData = [ + 'type' => 'someType2', + 'id' => $methodStoredId, + ]); + $collection = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [ + ['type' => 'someType'], + $methodData, + ]]); + + $result = $collection->fetchByPaymentMean($paymentMean); + + self::assertEquals($expectedPayment, $result); + } + + /** @test */ + public function it_can_filter_with_a_callback(): void + { + $collection = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [ + ['type' => $filteredType = 'someType'], + ['type' => 'otherType'], + ]]); + + $expected = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [ + ['type' => $filteredType], + ]]); + + $result = $collection->filter(static function(PaymentMethod $payment) use ($filteredType) { + return $filteredType === $payment->adyenType()->type(); + }); + + self::assertEquals($expected, $result); } } From 5451f4dcdd611be58f9715547d1b0fad1db2ddc2 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 6 Jan 2022 08:16:45 +0100 Subject: [PATCH 023/136] ASW-376 - CR fixes --- .../Payment/PaymentMethodCollectionTest.php | 87 ++----------------- 1 file changed, 9 insertions(+), 78 deletions(-) diff --git a/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php index b046f771..8f13a0e1 100644 --- a/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php +++ b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php @@ -8,18 +8,11 @@ use AdyenPayment\Collection\Payment\PaymentMethodCollection; use AdyenPayment\Models\Payment\PaymentMean; use AdyenPayment\Models\Payment\PaymentMethod; -use AdyenPayment\Utils\Sanitize; use PHPUnit\Framework\TestCase; use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; final class PaymentMethodCollectionTest extends TestCase { - /** @test */ - public function it_implements_countable(): void - { - self::assertInstanceOf(\Countable::class, new PaymentMethodCollection()); - } - /** @test */ public function it_implements_iterable(): void { @@ -27,19 +20,12 @@ public function it_implements_iterable(): void } /** @test */ - public function it_can_return_an_iterator(): void - { - $result = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [['type' => 'someType']]]); - - self::assertInstanceOf(\Traversable::class, $result->getIterator()); - } - - /** @test */ - public function it_can_count_the_payment_methods(): void + public function it_can_count(): void { $result = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [['type' => 'someType']]]); - self::assertEquals(1, $result->count()); + self::assertInstanceOf(\Countable::class, $result); + self::assertCount(1, $result); } /** @test */ @@ -59,7 +45,7 @@ public function it_can_map_with_a_callback(): void } /** @test */ - public function it_cam_map_to_raw(): void + public function it_can_map_to_raw(): void { $expected = [ ['type' => 'someType'], @@ -72,55 +58,6 @@ public function it_cam_map_to_raw(): void self::assertEquals($expected, $result); } - /** @test */ - public function it_can_fetch_by_identifier(): void - { - $paymentMethod = PaymentMethod::fromRaw($paymentMethodData = [ - 'type' => $type = 'someType', - 'name' => $name = 'someName', - ]); - $expectedMethod = $paymentMethod->withCode($name); - $paymentMethodsCollection = PaymentMethodCollection::fromAdyenMethods([ - 'paymentMethods' => [ - $paymentMethodData, - ['type' => 'anotherPaymentMethods'], - ], - ]); - $expectedCode = mb_strtolower(sprintf('%s_%s', $type, Sanitize::removeNonWord($name))); - $collectionWithCodes = $paymentMethodsCollection->withImportLocale($paymentMethodsCollection); - - $result = $collectionWithCodes->fetchByIdentifierOrStoredId($expectedCode); - - self::assertEquals($expectedMethod, $result); - } - - /** @test */ - public function it_can_fetch_by_stored_id(): void - { - $expectedPayment = PaymentMethod::fromRaw($methodData = [ - 'type' => 'someType2', - 'id' => $methodStoredId = 'methodWithId', - ]); - $collection = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [ - ['type' => 'someType'], - $methodData, - ]]); - - $result = $collection->fetchByIdentifierOrStoredId($methodStoredId); - - self::assertEquals($expectedPayment, $result); - } - - /** @test */ - public function it_will_return_null_if_method_not_found_by_identifier_or_stored_id(): void - { - $collection = new PaymentMethodCollection(); - - $result = $collection->fetchByIdentifierOrStoredId('missing-method'); - - self::assertNull($result); - } - /** @test */ public function it_can_map_adyen_payment_methods(): void { @@ -142,7 +79,7 @@ public function it_can_map_adyen_stored_payment_methods(): void } /** @test */ - public function it_can_map_import_locale(): void + public function it_can_enrich_with_import_locale(): void { $paymentMethod = PaymentMethod::fromRaw($paymentMethodData = [ 'type' => 'someType', @@ -184,18 +121,13 @@ public function it_can_fetch_a_method_by_payment_mean(): void 'source' => 1425514, 'attribute' => $attribute, ]); - $expectedPayment = PaymentMethod::fromRaw($methodData = [ - 'type' => 'someType2', - 'id' => $methodStoredId, - ]); - $collection = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [ - ['type' => 'someType'], - $methodData, - ]]); + $testPayment = PaymentMethod::fromRaw(['type' => 'someType']); + $expectedPayment = PaymentMethod::fromRaw(['type' => 'someType2', 'id' => $methodStoredId]); + $collection = new PaymentMethodCollection($testPayment, $expectedPayment); $result = $collection->fetchByPaymentMean($paymentMean); - self::assertEquals($expectedPayment, $result); + self::assertSame($expectedPayment, $result); } /** @test */ @@ -205,7 +137,6 @@ public function it_can_filter_with_a_callback(): void ['type' => $filteredType = 'someType'], ['type' => 'otherType'], ]]); - $expected = PaymentMethodCollection::fromAdyenMethods(['paymentMethods' => [ ['type' => $filteredType], ]]); From 8a4adfc47d15f11519e9f038e3546e5ef6ff366e Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 14 Jan 2022 09:13:22 +0100 Subject: [PATCH 024/136] ASW-378 - Disabled stored methods pick --- .../frontend/register/payment_fieldset.tpl | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Resources/views/frontend/register/payment_fieldset.tpl diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl new file mode 100644 index 00000000..aa94ca8b --- /dev/null +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -0,0 +1,46 @@ +{extends file='parent:frontend/register/payment_fieldset.tpl'} + +{block name="frontend_register_payment_fieldset"} +
+ {foreach $payment_means as $payment_mean} + {assign var='isStoredPayment' value=('isStoredPayment'|array_key_exists:$payment_mean && true === $payment_mean.isStoredPayment)} + + {block name="frontend_register_payment_method"} +
+ + {block name="frontend_register_payment_fieldset_input"} +
+ {if not $isStoredPayment} + {block name="frontend_register_payment_fieldset_input_radio"} + + {/block} + {/if} +
+
+ {block name="frontend_register_payment_fieldset_input_label"} + + {$payment_mean.description} + + {/block} +
+ {/block} + + {block name="frontend_register_payment_fieldset_description"} +
+ {include file="string:{$payment_mean.additionaldescription}"} +
+ {/block} + + {block name='frontend_register_payment_fieldset_template'} +
+ {if "frontend/plugins/payment/`$payment_mean.template`"|template_exists} +
+ {include file="frontend/plugins/payment/`$payment_mean.template`" checked = ($payment_mean.id == $form_data.payment)} +
+ {/if} + {/block} +
+ {/block} + {/foreach} +
+{/block} From a4a719d19fc822850e29dbba5aa778579983e36f Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 14 Jan 2022 12:07:10 +0100 Subject: [PATCH 025/136] ASW-378 - Template fix --- .../frontend/register/payment_fieldset.tpl | 53 ++++--------------- 1 file changed, 11 insertions(+), 42 deletions(-) diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl index aa94ca8b..e3217d28 100644 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -1,46 +1,15 @@ {extends file='parent:frontend/register/payment_fieldset.tpl'} -{block name="frontend_register_payment_fieldset"} -
- {foreach $payment_means as $payment_mean} - {assign var='isStoredPayment' value=('isStoredPayment'|array_key_exists:$payment_mean && true === $payment_mean.isStoredPayment)} - - {block name="frontend_register_payment_method"} -
- - {block name="frontend_register_payment_fieldset_input"} -
- {if not $isStoredPayment} - {block name="frontend_register_payment_fieldset_input_radio"} - - {/block} - {/if} -
-
- {block name="frontend_register_payment_fieldset_input_label"} - - {$payment_mean.description} - - {/block} -
- {/block} - - {block name="frontend_register_payment_fieldset_description"} -
- {include file="string:{$payment_mean.additionaldescription}"} -
- {/block} +{block name="frontend_register_payment_fieldset_input_radio"} + {assign var='isStoredPayment' value=('isStoredPayment'|array_key_exists:$payment_mean && true === $payment_mean.isStoredPayment)} + {if not $isStoredPayment} + + {/if} +{/block} - {block name='frontend_register_payment_fieldset_template'} -
- {if "frontend/plugins/payment/`$payment_mean.template`"|template_exists} -
- {include file="frontend/plugins/payment/`$payment_mean.template`" checked = ($payment_mean.id == $form_data.payment)} -
- {/if} - {/block} -
- {/block} - {/foreach} -
+{block name="frontend_register_payment_fieldset_input_label"} + {assign var='isStoredPayment' value=('isStoredPayment'|array_key_exists:$payment_mean && true === $payment_mean.isStoredPayment)} + + {$payment_mean.description} + {/block} From 3ed8fa526277c3febff4ebbb02f53b2939e1d41a Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 5 Jan 2022 13:09:21 +0100 Subject: [PATCH 026/136] ASW-377 - EnrichedPaymentMeanProvider for stored methods --- .../EnrichedPaymentMeanProvider.php | 48 +++++++++++++++++-- .../EnrichedPaymentMeanProviderTest.php | 2 + 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php index 8d327415..02162997 100644 --- a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php @@ -4,12 +4,16 @@ namespace AdyenPayment\Components\Adyen\PaymentMethod; +use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; +use AdyenPayment\Collection\Payment\PaymentMethodCollection; use AdyenPayment\Components\Adyen\Builder\PaymentMethodOptionsBuilderInterface; use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use AdyenPayment\Enricher\Payment\PaymentMethodEnricherInterface; use AdyenPayment\Models\Enum\PaymentMethod\SourceType; +use AdyenPayment\Models\Payment\PaymentGroup; use AdyenPayment\Models\Payment\PaymentMean; +use AdyenPayment\Models\Payment\PaymentMethod; final class EnrichedPaymentMeanProvider implements EnrichedPaymentMeanProviderInterface { @@ -40,9 +44,29 @@ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollec $paymentMethodOptions['value'] ); + /** @var ?PaymentMean $umbrellaPaymentMean */ + $umbrellaPaymentMean = $paymentMeans->map(static function(PaymentMean $method) { + if (AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE === $method->getRaw()['name']) { + return $method; + } + })[0] ?? null; + + return new PaymentMeanCollection( + ...$this->createAdyenPaymentMeans($paymentMeans, $adyenPaymentMethods), + ...(null === $umbrellaPaymentMean ? [] : $this->createAdyenStoredPaymentMeans( + $adyenPaymentMethods, + $umbrellaPaymentMean + )) + ); + } + + private function createAdyenPaymentMeans( + PaymentMeanCollection $paymentMeans, + PaymentMethodCollection $adyenPaymentMethods + ): array { $enricher = $this->paymentMethodEnricher; - return new PaymentMeanCollection(...$paymentMeans + return $paymentMeans ->filterExcludeHidden() ->map(static function(PaymentMean $paymentMean) use ($adyenPaymentMethods, $enricher): ?PaymentMean { if (!$paymentMean->getSource()->equals(SourceType::adyen())) { @@ -57,7 +81,25 @@ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollec return PaymentMean::createFromShopwareArray( ($enricher)($paymentMean->getRaw(), $paymentMethod) ); - }) - ); + }); + } + + private function createAdyenStoredPaymentMeans( + PaymentMethodCollection $adyenPaymentMethods, + PaymentMean $umbrellaPaymentMean + ): array { + $enricher = $this->paymentMethodEnricher; + $storedAdyenMethods = $adyenPaymentMethods->filterByPaymentType(PaymentGroup::stored()); + + return $storedAdyenMethods->map(static function(PaymentMethod $paymentMethod) use ($umbrellaPaymentMean, $enricher): PaymentMean { + $shopwareMethod = $umbrellaPaymentMean->getRaw(); + $shopwareMethod['name'] = $shopwareMethod['description'] = $paymentMethod->getValue('name'); + $shopwareMethod[AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE.'_id'] = $shopwareMethod['id']; + $shopwareMethod['id'] = $paymentMethod->getStoredPaymentMethodId(); + + return PaymentMean::createFromShopwareArray( + ($enricher)($shopwareMethod, $paymentMethod) + ); + }); } } diff --git a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php index 40f2a3fc..d9b483bf 100644 --- a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php +++ b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php @@ -42,6 +42,8 @@ class EnrichedPaymentMeanProviderTest extends TestCase protected function setUp(): void { + // @TODO - ASW-377: refactor test to match new code on the EnrichedPaymentMeanProvider class. + $this->markTestSkipped('@TODO - ASW-377'); $this->paymentMethodService = $this->prophesize(PaymentMethodServiceInterface::class); $this->paymentMethodOptionsBuilder = $this->prophesize(PaymentMethodOptionsBuilderInterface::class); $this->paymentMethodEnricher = $this->prophesize(PaymentMethodEnricherInterface::class); From c16ab909e92e2da97c9bffb11fb96bbdc9cc2320 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 6 Jan 2022 13:03:29 +0100 Subject: [PATCH 027/136] ASW-377 - Stored methods selection --- Collection/Payment/PaymentMeanCollection.php | 12 +++++ .../EnrichedPaymentMeanProvider.php | 44 +++++++------------ Enricher/Payment/PaymentMethodEnricher.php | 14 ++++-- .../UmbrellaPaymentMeanNotFoundException.php | 13 ++++++ .../js/jquery.adyen-payment-selection.js | 12 ++++- .../frontend/checkout/change_payment.tpl | 1 + 6 files changed, 65 insertions(+), 31 deletions(-) create mode 100644 Exceptions/UmbrellaPaymentMeanNotFoundException.php diff --git a/Collection/Payment/PaymentMeanCollection.php b/Collection/Payment/PaymentMeanCollection.php index aaeae418..e2b5ee94 100644 --- a/Collection/Payment/PaymentMeanCollection.php +++ b/Collection/Payment/PaymentMeanCollection.php @@ -4,6 +4,7 @@ namespace AdyenPayment\Collection\Payment; +use AdyenPayment\AdyenPayment; use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMean; @@ -81,6 +82,17 @@ public function filterByAdyenSource(): self return $this->filterBySource(SourceType::adyen()); } + public function fetchUmbrellaMean(): ?PaymentMean + { + foreach ($this->paymentMeans as $paymentMean) { + if (AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE === $paymentMean->getRaw()['name']) { + return $paymentMean; + } + } + + return null; + } + public function toShopwareArray(): array { return array_reduce($this->paymentMeans, static function(array $payload, PaymentMean $paymentMean): array { diff --git a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php index 02162997..1c1bd5c3 100644 --- a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php @@ -4,12 +4,12 @@ namespace AdyenPayment\Components\Adyen\PaymentMethod; -use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Collection\Payment\PaymentMethodCollection; use AdyenPayment\Components\Adyen\Builder\PaymentMethodOptionsBuilderInterface; use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use AdyenPayment\Enricher\Payment\PaymentMethodEnricherInterface; +use AdyenPayment\Exceptions\UmbrellaPaymentMeanNotFoundException; use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentGroup; use AdyenPayment\Models\Payment\PaymentMean; @@ -44,23 +44,18 @@ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollec $paymentMethodOptions['value'] ); - /** @var ?PaymentMean $umbrellaPaymentMean */ - $umbrellaPaymentMean = $paymentMeans->map(static function(PaymentMean $method) { - if (AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE === $method->getRaw()['name']) { - return $method; - } - })[0] ?? null; + $umbrellaPaymentMean = $paymentMeans->fetchUmbrellaMean(); + if (null === $umbrellaPaymentMean) { + throw UmbrellaPaymentMeanNotFoundException::missingUmbrellaPaymentMean(); + } return new PaymentMeanCollection( - ...$this->createAdyenPaymentMeans($paymentMeans, $adyenPaymentMethods), - ...(null === $umbrellaPaymentMean ? [] : $this->createAdyenStoredPaymentMeans( - $adyenPaymentMethods, - $umbrellaPaymentMean - )) + ...$this->provideEnrichedPaymentMeans($paymentMeans, $adyenPaymentMethods), + ...$this->provideEnrichedStoredPaymentMeans($adyenPaymentMethods, $umbrellaPaymentMean) ); } - private function createAdyenPaymentMeans( + private function provideEnrichedPaymentMeans( PaymentMeanCollection $paymentMeans, PaymentMethodCollection $adyenPaymentMethods ): array { @@ -78,28 +73,23 @@ private function createAdyenPaymentMeans( return null; } - return PaymentMean::createFromShopwareArray( - ($enricher)($paymentMean->getRaw(), $paymentMethod) - ); + return PaymentMean::createFromShopwareArray(($enricher)($paymentMean->getRaw(), $paymentMethod)); }); } - private function createAdyenStoredPaymentMeans( + private function provideEnrichedStoredPaymentMeans( PaymentMethodCollection $adyenPaymentMethods, PaymentMean $umbrellaPaymentMean ): array { $enricher = $this->paymentMethodEnricher; $storedAdyenMethods = $adyenPaymentMethods->filterByPaymentType(PaymentGroup::stored()); - return $storedAdyenMethods->map(static function(PaymentMethod $paymentMethod) use ($umbrellaPaymentMean, $enricher): PaymentMean { - $shopwareMethod = $umbrellaPaymentMean->getRaw(); - $shopwareMethod['name'] = $shopwareMethod['description'] = $paymentMethod->getValue('name'); - $shopwareMethod[AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE.'_id'] = $shopwareMethod['id']; - $shopwareMethod['id'] = $paymentMethod->getStoredPaymentMethodId(); - - return PaymentMean::createFromShopwareArray( - ($enricher)($shopwareMethod, $paymentMethod) - ); - }); + return $storedAdyenMethods->map( + static function(PaymentMethod $paymentMethod) use ($umbrellaPaymentMean, $enricher): PaymentMean { + return PaymentMean::createFromShopwareArray( + ($enricher)($umbrellaPaymentMean->getRaw(), $paymentMethod) + ); + } + ); } } diff --git a/Enricher/Payment/PaymentMethodEnricher.php b/Enricher/Payment/PaymentMethodEnricher.php index 45edbc9c..d7947b12 100644 --- a/Enricher/Payment/PaymentMethodEnricher.php +++ b/Enricher/Payment/PaymentMethodEnricher.php @@ -25,16 +25,24 @@ public function __invoke(array $shopwareMethod, PaymentMethod $paymentMethod): a { return array_merge($shopwareMethod, [ 'enriched' => true, - 'additionaldescription' => $this->enrichDescription($paymentMethod), + 'additionaldescription' => $this->enrichAdditionalDescription($paymentMethod), 'image' => $this->imageLogoProvider->provideByType($paymentMethod->adyenType()->type()), 'isStoredPayment' => $paymentMethod->isStoredPayment(), 'isAdyenPaymentMethod' => true, 'adyenType' => $paymentMethod->adyenType()->type(), 'metadata' => $paymentMethod->rawData(), - ]); + 'stored_method_umbrella_id' => $paymentMethod->isStoredPayment() ? sprintf( + '%s_%s', + $shopwareMethod['id'], + $paymentMethod->getStoredPaymentMethodId() + ) : null, + 'stored_method_id' => $paymentMethod->isStoredPayment() ? $paymentMethod->getStoredPaymentMethodId() : null, + ], + $paymentMethod->isStoredPayment() ? ['description' => $paymentMethod->getValue('name')] : [] + ); } - private function enrichDescription(PaymentMethod $adyenMethod): string + private function enrichAdditionalDescription(PaymentMethod $adyenMethod): string { $description = $this->snippets ->getNamespace('adyen/method/description') diff --git a/Exceptions/UmbrellaPaymentMeanNotFoundException.php b/Exceptions/UmbrellaPaymentMeanNotFoundException.php new file mode 100644 index 00000000..2982414a --- /dev/null +++ b/Exceptions/UmbrellaPaymentMeanNotFoundException.php @@ -0,0 +1,13 @@ + Date: Mon, 10 Jan 2022 13:22:07 +0100 Subject: [PATCH 028/136] ASW-377 - Payment mean selection --- Enricher/Payment/PaymentMethodEnricher.php | 22 ++++-- .../js/jquery.adyen-payment-selection.js | 11 ++- Resources/services/subscribers.xml | 6 +- ...chViewDataForUmbrellaPaymentSubscriber.php | 68 +++++++++++++++++++ 4 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 Subscriber/Checkout/EnrichViewDataForUmbrellaPaymentSubscriber.php diff --git a/Enricher/Payment/PaymentMethodEnricher.php b/Enricher/Payment/PaymentMethodEnricher.php index d7947b12..0b8327e9 100644 --- a/Enricher/Payment/PaymentMethodEnricher.php +++ b/Enricher/Payment/PaymentMethodEnricher.php @@ -4,8 +4,10 @@ namespace AdyenPayment\Enricher\Payment; +use AdyenPayment\AdyenPayment; use AdyenPayment\Components\Adyen\PaymentMethod\ImageLogoProviderInterface; use AdyenPayment\Models\Payment\PaymentMethod; +use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; use Shopware_Components_Snippet_Manager; final class PaymentMethodEnricher implements PaymentMethodEnricherInterface @@ -23,6 +25,13 @@ public function __construct( public function __invoke(array $shopwareMethod, PaymentMethod $paymentMethod): array { + /** @TODO - ASW-377: WIP, clean up. */ + $storedMethodUmbrellaId = $paymentMethod->isStoredPayment() ? sprintf( + '%s_%s', + $shopwareMethod['id'], + $paymentMethod->getStoredPaymentMethodId() + ) : null; + return array_merge($shopwareMethod, [ 'enriched' => true, 'additionaldescription' => $this->enrichAdditionalDescription($paymentMethod), @@ -31,14 +40,15 @@ public function __invoke(array $shopwareMethod, PaymentMethod $paymentMethod): a 'isAdyenPaymentMethod' => true, 'adyenType' => $paymentMethod->adyenType()->type(), 'metadata' => $paymentMethod->rawData(), - 'stored_method_umbrella_id' => $paymentMethod->isStoredPayment() ? sprintf( - '%s_%s', - $shopwareMethod['id'], - $paymentMethod->getStoredPaymentMethodId() - ) : null, + 'stored_method_umbrella_id' => $storedMethodUmbrellaId, 'stored_method_id' => $paymentMethod->isStoredPayment() ? $paymentMethod->getStoredPaymentMethodId() : null, ], - $paymentMethod->isStoredPayment() ? ['description' => $paymentMethod->getValue('name')] : [] + $paymentMethod->isStoredPayment() ? [ + 'description' => $paymentMethod->getValue('name'), + 'attribute' => new Attribute([ + AdyenPayment::ADYEN_STORED_METHOD_ID => $paymentMethod->getStoredPaymentMethodId(), + ]), + ] : [] ); } diff --git a/Resources/frontend/js/jquery.adyen-payment-selection.js b/Resources/frontend/js/jquery.adyen-payment-selection.js index 615ac880..305a4206 100644 --- a/Resources/frontend/js/jquery.adyen-payment-selection.js +++ b/Resources/frontend/js/jquery.adyen-payment-selection.js @@ -126,6 +126,8 @@ e.preventDefault(); return false; } + var $paymentElement = $('.payment--method [name="payment"]:checked')[0]; + $paymentElement.value = this.extractShopwarePaymentId($paymentElement.value); }, isPaymentElement: function (elementId) { return $('#' + elementId).parents(this.opts.paymentMethodSelector).length > 0; @@ -142,7 +144,7 @@ } me.selectedPaymentElementId = selectedPaymentElementId; - me.selectedPaymentId = me.extractShopwarePaymentId($(event.target).val()); + me.selectedPaymentId = me.extractStoredPaymentId($(event.target).val()); var paymentMethodSession = this.getPaymentSession(); if (0 === Object.keys(paymentMethodSession).length) { @@ -158,6 +160,13 @@ return targetElementValue; } + return targetElementValue.split('_')[0]; + }, + extractStoredPaymentId: function (targetElementValue) { + if(-1 === targetElementValue.indexOf('_')){ + return targetElementValue; + } + return targetElementValue.split('_')[1]; }, onPaymentChangedAfter: function () { diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index d419e802..aea04fb2 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -90,7 +90,11 @@
- + + + + + diff --git a/Subscriber/Checkout/EnrichViewDataForUmbrellaPaymentSubscriber.php b/Subscriber/Checkout/EnrichViewDataForUmbrellaPaymentSubscriber.php new file mode 100644 index 00000000..f7088582 --- /dev/null +++ b/Subscriber/Checkout/EnrichViewDataForUmbrellaPaymentSubscriber.php @@ -0,0 +1,68 @@ +enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + } + + public static function getSubscribedEvents(): array + { + return [ + 'Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke', + ]; + } + + public function __invoke(\Enlight_Controller_ActionEventArgs $args): void + { + /** + * @TODO - ASW-377: WIP, technically this is the same as EnrichUserAdditionalPaymentSubscriber. + * Created a new subscriber to easily remove it if not needed, but at the end we need to fix the ID for + * the shippingPaymentAction as well. + */ + $subject = $args->getSubject(); + if ('shippingPayment' !== $subject->Request()->getActionName() || $subject->Request()->getParam('isXHR')) { + return; + } + + $userData = $subject->View()->getAssign('sUserData') ?? []; + + // @TODO: WIP - TEST. + $paymentMean = PaymentMean::createFromShopwareArray( + $userData['additional']['payment'] ?? [] + ); + if (!$paymentMean->getId()) { + return; + } + + $isUmbrellaMethod = AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE === $paymentMean->getValue('name'); + if (!$isUmbrellaMethod) { + return; + } + + $paymentMeans = ($this->enrichedPaymentMeanProvider)(new PaymentMeanCollection($paymentMean)); + /** @var PaymentMean $paymentMean */ + $paymentMean = iterator_to_array($paymentMeans->getIterator())[0]; + $userData['additional']['payment'] = $paymentMean->getRaw(); + + $storedMethodUmbrellaId = $userData['additional']['payment']['stored_method_umbrella_id'] ?? null; + if (null === $storedMethodUmbrellaId) { + return; + } + + $subject->View()->assign('sFormData', ['payment' => $storedMethodUmbrellaId]); + } +} From a4d6a1b60c7818314a2137005710aff75a09b4cf Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 11 Jan 2022 13:24:42 +0100 Subject: [PATCH 029/136] ASW-377 - Subscribers and session handler --- AdyenPayment.php | 4 +- Collection/Payment/PaymentMeanCollection.php | 22 ++++++ Enricher/Payment/PaymentMethodEnricher.php | 15 ++-- Models/PaymentInfo.php | 18 +++++ .../js/jquery.adyen-payment-selection.js | 39 +++++------ Resources/services/subscribers.xml | 8 ++- .../EnrichUmbrellaPaymentMeanSubscriber.php | 61 +++++++++++++++++ .../EnrichUserAdditionalPaymentSubscriber.php | 31 ++++++--- ...chViewDataForUmbrellaPaymentSubscriber.php | 68 ------------------- .../PersistStoredMethodIdSubscriber.php | 38 +++++++++++ 10 files changed, 194 insertions(+), 110 deletions(-) create mode 100644 Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php delete mode 100644 Subscriber/Checkout/EnrichViewDataForUmbrellaPaymentSubscriber.php create mode 100644 Subscriber/Checkout/PersistStoredMethodIdSubscriber.php diff --git a/AdyenPayment.php b/AdyenPayment.php index cd46af00..3410120f 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -206,8 +206,8 @@ private function installStoredPaymentUmbrella(InstallContext $context): void $payment->setSource(SourceType::adyen()->getType()); $payment->setHide(true); $payment->setPluginId($context->getPlugin()->getId()); - $payment->setDescription(self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE); - $payment->setAdditionalDescription(self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE); + $payment->setDescription($description = 'Adyen Stored Payment Method'); + $payment->setAdditionalDescription($description); $paymentId = $database->fetchRow( 'SELECT `id` FROM `s_core_paymentmeans` WHERE `name` = :name', diff --git a/Collection/Payment/PaymentMeanCollection.php b/Collection/Payment/PaymentMeanCollection.php index e2b5ee94..0d1242d6 100644 --- a/Collection/Payment/PaymentMeanCollection.php +++ b/Collection/Payment/PaymentMeanCollection.php @@ -93,6 +93,28 @@ public function fetchUmbrellaMean(): ?PaymentMean return null; } + public function fetchByStoredMethodUmbrellaId(string $storedMethodId): ?PaymentMean + { + foreach ($this->paymentMeans as $paymentMean) { + if ($storedMethodId === ($paymentMean->getRaw()['stored_method_id'] ?? null)) { + return $paymentMean; + } + } + + return null; + } + + public function fetchById(int $id): ?PaymentMean + { + foreach ($this->paymentMeans as $paymentMean) { + if ($id === $paymentMean->getId()) { + return $paymentMean; + } + } + + return null; + } + public function toShopwareArray(): array { return array_reduce($this->paymentMeans, static function(array $payload, PaymentMean $paymentMean): array { diff --git a/Enricher/Payment/PaymentMethodEnricher.php b/Enricher/Payment/PaymentMethodEnricher.php index 0b8327e9..91b78335 100644 --- a/Enricher/Payment/PaymentMethodEnricher.php +++ b/Enricher/Payment/PaymentMethodEnricher.php @@ -6,6 +6,7 @@ use AdyenPayment\AdyenPayment; use AdyenPayment\Components\Adyen\PaymentMethod\ImageLogoProviderInterface; +use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMethod; use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; use Shopware_Components_Snippet_Manager; @@ -25,13 +26,6 @@ public function __construct( public function __invoke(array $shopwareMethod, PaymentMethod $paymentMethod): array { - /** @TODO - ASW-377: WIP, clean up. */ - $storedMethodUmbrellaId = $paymentMethod->isStoredPayment() ? sprintf( - '%s_%s', - $shopwareMethod['id'], - $paymentMethod->getStoredPaymentMethodId() - ) : null; - return array_merge($shopwareMethod, [ 'enriched' => true, 'additionaldescription' => $this->enrichAdditionalDescription($paymentMethod), @@ -40,11 +34,16 @@ public function __invoke(array $shopwareMethod, PaymentMethod $paymentMethod): a 'isAdyenPaymentMethod' => true, 'adyenType' => $paymentMethod->adyenType()->type(), 'metadata' => $paymentMethod->rawData(), - 'stored_method_umbrella_id' => $storedMethodUmbrellaId, + 'stored_method_umbrella_id' => $paymentMethod->isStoredPayment() ? sprintf( + '%s_%s', + $shopwareMethod['id'], + $paymentMethod->getStoredPaymentMethodId() + ) : null, 'stored_method_id' => $paymentMethod->isStoredPayment() ? $paymentMethod->getStoredPaymentMethodId() : null, ], $paymentMethod->isStoredPayment() ? [ 'description' => $paymentMethod->getValue('name'), + 'source' => SourceType::adyen()->getType(), 'attribute' => new Attribute([ AdyenPayment::ADYEN_STORED_METHOD_ID => $paymentMethod->getStoredPaymentMethodId(), ]), diff --git a/Models/PaymentInfo.php b/Models/PaymentInfo.php index a5acf094..1006f4d7 100644 --- a/Models/PaymentInfo.php +++ b/Models/PaymentInfo.php @@ -79,6 +79,12 @@ class PaymentInfo extends ModelEntity */ private $paymentData; + /** + * @var string + * @ORM\Column(name="stored_method_id", type="text", nullable=true) + */ + private $storedMethodId; + public function __construct() { $this->setCreatedAt(new \DateTime('now')); @@ -279,4 +285,16 @@ public function setPaymentData(string $paymentData): self return $this; } + + public function getStoredMethodId(): string + { + return $this->storedMethodId; + } + + public function setStoredMethodId(string $storedMethodId): self + { + $this->storedMethodId = $storedMethodId; + + return $this; + } } diff --git a/Resources/frontend/js/jquery.adyen-payment-selection.js b/Resources/frontend/js/jquery.adyen-payment-selection.js index 305a4206..4972e315 100644 --- a/Resources/frontend/js/jquery.adyen-payment-selection.js +++ b/Resources/frontend/js/jquery.adyen-payment-selection.js @@ -122,12 +122,19 @@ }, onPaymentFormSubmit: function (e) { var me = this; - if ($(me.opts.paymentMethodFormSubmitSelector).hasClass('is--disabled')) { + let $formSubmit = $(me.opts.paymentMethodFormSubmitSelector); + if ($formSubmit.hasClass('is--disabled')) { e.preventDefault(); return false; } var $paymentElement = $('.payment--method [name="payment"]:checked')[0]; - $paymentElement.value = this.extractShopwarePaymentId($paymentElement.value); + var paymentMethod = this.getPaymentMethodById($paymentElement.value); + if(paymentMethod.isStoredPayment){ + var $storedMethodElement = $(''); + $storedMethodElement.val(paymentMethod.stored_method_id); + $formSubmit.append($storedMethodElement); + } + $paymentElement.value = paymentMethod.id; }, isPaymentElement: function (elementId) { return $('#' + elementId).parents(this.opts.paymentMethodSelector).length > 0; @@ -144,7 +151,10 @@ } me.selectedPaymentElementId = selectedPaymentElementId; - me.selectedPaymentId = me.extractStoredPaymentId($(event.target).val()); + + var elementValue = $(event.target).val(); + var paymentMethod = this.getPaymentMethodById(elementValue); + me.selectedPaymentId = paymentMethod.isStoredPayment ? paymentMethod.stored_method_id : elementValue; var paymentMethodSession = this.getPaymentSession(); if (0 === Object.keys(paymentMethodSession).length) { @@ -155,20 +165,6 @@ me.clearPaymentSession(); } }, - extractShopwarePaymentId: function (targetElementValue) { - if(-1 === targetElementValue.indexOf('_')){ - return targetElementValue; - } - - return targetElementValue.split('_')[0]; - }, - extractStoredPaymentId: function (targetElementValue) { - if(-1 === targetElementValue.indexOf('_')){ - return targetElementValue; - } - - return targetElementValue.split('_')[1]; - }, onPaymentChangedAfter: function () { var me = this; @@ -250,11 +246,10 @@ getPaymentMethodById: function (id) { var me = this; - return me.opts.enrichedPaymentMethods.filter(function(enrichedPaymentMethod) { - if(enrichedPaymentMethod.isStoredPayment === true && enrichedPaymentMethod.stored_method_id === id){ - return true; - } - return enrichedPaymentMethod.id === id; + return me.opts.enrichedPaymentMethods.filter(function(paymentMethod) { + return paymentMethod.id === id || ( + paymentMethod.isStoredPayment === true + && (paymentMethod.stored_method_id === id || paymentMethod.stored_method_umbrella_id === id)); })[0] || {}; }, /** diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index aea04fb2..8d5244c6 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -91,10 +91,16 @@ + - + + + + + + diff --git a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php new file mode 100644 index 00000000..7fec04aa --- /dev/null +++ b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php @@ -0,0 +1,61 @@ +enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + $this->session = $session; + } + + public static function getSubscribedEvents(): array + { + return [ + 'Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke', + ]; + } + + public function __invoke(\Enlight_Controller_ActionEventArgs $args): void + { + $subject = $args->getSubject(); + $actionName = $subject->Request()->getActionName(); + $isShippingPaymentView = 'shippingPayment' === $actionName && !$subject->Request()->getParam('isXHR'); + if (!$isShippingPaymentView) { + return; + } + + $storedMethodId = $this->session->get('storedMethodId'); + if (null === $storedMethodId) { + return; + } + + $admin = Shopware()->Modules()->Admin(); + $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( + PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()) + ); + + $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodUmbrellaId($storedMethodId); + if (null === $paymentMean) { + return; + } + + $userData = $subject->View()->getAssign('sUserData'); + $userData['additional']['payment'] = $paymentMean->getRaw(); + $subject->View()->assign('sUserData', $userData); + $subject->View()->assign('sFormData', ['payment' => $paymentMean->getRaw()['stored_method_umbrella_id']]); + } +} diff --git a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php index a050a9e8..e1c22822 100644 --- a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php +++ b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php @@ -6,16 +6,20 @@ use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProviderInterface; -use AdyenPayment\Models\Payment\PaymentMean; use Enlight\Event\SubscriberInterface; +use Enlight_Components_Session_Namespace; final class EnrichUserAdditionalPaymentSubscriber implements SubscriberInterface { private EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider; + private Enlight_Components_Session_Namespace $session; - public function __construct(EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider) - { + public function __construct( + EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider, + Enlight_Components_Session_Namespace $session + ) { $this->enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + $this->session = $session; } public static function getSubscribedEvents(): array @@ -33,17 +37,26 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } + $storedMethodId = $this->session->get('storedMethodId'); $userData = $subject->View()->getAssign('sUserData'); - $paymentMean = PaymentMean::createFromShopwareArray( - $subject->View()->getAssign('sUserData')['additional']['payment'] ?? [] + $paymentMeanId = $userData['additional']['payment']['id'] ?? null; + + if (null === $storedMethodId && null === $paymentMeanId) { + return; + } + + $admin = Shopware()->Modules()->Admin(); + $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( + PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()) ); - if (!$paymentMean->getId()) { + + $paymentMean = null === $storedMethodId + ? $enrichedPaymentMeans->fetchById((int) $paymentMeanId) + : $enrichedPaymentMeans->fetchByStoredMethodUmbrellaId($storedMethodId); + if (null === $paymentMean) { return; } - $paymentMeans = ($this->enrichedPaymentMeanProvider)(new PaymentMeanCollection($paymentMean)); - /** @var PaymentMean $paymentMean */ - $paymentMean = iterator_to_array($paymentMeans->getIterator())[0]; $userData['additional']['payment'] = $paymentMean->getRaw(); $subject->View()->assign('sUserData', $userData); } diff --git a/Subscriber/Checkout/EnrichViewDataForUmbrellaPaymentSubscriber.php b/Subscriber/Checkout/EnrichViewDataForUmbrellaPaymentSubscriber.php deleted file mode 100644 index f7088582..00000000 --- a/Subscriber/Checkout/EnrichViewDataForUmbrellaPaymentSubscriber.php +++ /dev/null @@ -1,68 +0,0 @@ -enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; - } - - public static function getSubscribedEvents(): array - { - return [ - 'Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke', - ]; - } - - public function __invoke(\Enlight_Controller_ActionEventArgs $args): void - { - /** - * @TODO - ASW-377: WIP, technically this is the same as EnrichUserAdditionalPaymentSubscriber. - * Created a new subscriber to easily remove it if not needed, but at the end we need to fix the ID for - * the shippingPaymentAction as well. - */ - $subject = $args->getSubject(); - if ('shippingPayment' !== $subject->Request()->getActionName() || $subject->Request()->getParam('isXHR')) { - return; - } - - $userData = $subject->View()->getAssign('sUserData') ?? []; - - // @TODO: WIP - TEST. - $paymentMean = PaymentMean::createFromShopwareArray( - $userData['additional']['payment'] ?? [] - ); - if (!$paymentMean->getId()) { - return; - } - - $isUmbrellaMethod = AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE === $paymentMean->getValue('name'); - if (!$isUmbrellaMethod) { - return; - } - - $paymentMeans = ($this->enrichedPaymentMeanProvider)(new PaymentMeanCollection($paymentMean)); - /** @var PaymentMean $paymentMean */ - $paymentMean = iterator_to_array($paymentMeans->getIterator())[0]; - $userData['additional']['payment'] = $paymentMean->getRaw(); - - $storedMethodUmbrellaId = $userData['additional']['payment']['stored_method_umbrella_id'] ?? null; - if (null === $storedMethodUmbrellaId) { - return; - } - - $subject->View()->assign('sFormData', ['payment' => $storedMethodUmbrellaId]); - } -} diff --git a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php new file mode 100644 index 00000000..9b801ee4 --- /dev/null +++ b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php @@ -0,0 +1,38 @@ +session = $session; + } + + public static function getSubscribedEvents(): array + { + return [ + 'Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke', + ]; + } + + public function __invoke(\Enlight_Controller_ActionEventArgs $args): void + { + $subject = $args->getSubject(); + $actionName = $subject->Request()->getActionName(); + $isShippingPaymentUpdate = 'shippingPayment' === $actionName && $subject->Request()->getParam('isXHR'); + $isSaveShippingPayment = 'saveShippingPayment' === $actionName; + $storedMethodId = $subject->Request()->getParam('storedMethodId'); + if (null !== $storedMethodId && ($isShippingPaymentUpdate || $isSaveShippingPayment)) { + $this->session->set('storedMethodId', $storedMethodId); + } + } +} From 76d4c9e1531262eca6e68f76a3162c45c6f8daef Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 12 Jan 2022 10:13:58 +0100 Subject: [PATCH 030/136] ASW-377 - CR fixes --- AdyenPayment.php | 1 + Collection/Payment/PaymentMeanCollection.php | 10 +++--- .../EnrichedPaymentMeanProvider.php | 2 +- Enricher/Payment/PaymentMethodEnricher.php | 35 ++++++++++++------- .../js/jquery.adyen-payment-selection.js | 10 +++--- .../EnrichUmbrellaPaymentMeanSubscriber.php | 7 ++-- .../EnrichUserAdditionalPaymentSubscriber.php | 28 ++++++++------- .../PersistStoredMethodIdSubscriber.php | 9 +++-- 8 files changed, 59 insertions(+), 43 deletions(-) diff --git a/AdyenPayment.php b/AdyenPayment.php index 3410120f..58e74888 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -36,6 +36,7 @@ final class AdyenPayment extends Plugin public const ADYEN_STORED_PAYMENT_UMBRELLA_CODE = 'adyen_stored_payment_umbrella'; public const SESSION_ADYEN_RESTRICT_EMAILS = 'adyenRestrictEmail'; public const SESSION_ADYEN_PAYMENT_INFO_ID = 'adyenPaymentInfoId'; + public const SESSION_ADYEN_STORED_METHOD_ID = 'adyenStoredMethodId'; public static function isPackage(): bool { diff --git a/Collection/Payment/PaymentMeanCollection.php b/Collection/Payment/PaymentMeanCollection.php index 0d1242d6..c2ae15f4 100644 --- a/Collection/Payment/PaymentMeanCollection.php +++ b/Collection/Payment/PaymentMeanCollection.php @@ -82,10 +82,10 @@ public function filterByAdyenSource(): self return $this->filterBySource(SourceType::adyen()); } - public function fetchUmbrellaMean(): ?PaymentMean + public function fetchStoredMethodUmbrellaPaymentMean(): ?PaymentMean { foreach ($this->paymentMeans as $paymentMean) { - if (AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE === $paymentMean->getRaw()['name']) { + if (AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE === $paymentMean->getValue('name')) { return $paymentMean; } } @@ -93,10 +93,10 @@ public function fetchUmbrellaMean(): ?PaymentMean return null; } - public function fetchByStoredMethodUmbrellaId(string $storedMethodId): ?PaymentMean + public function fetchByStoredMethodId(string $storedMethodId): ?PaymentMean { foreach ($this->paymentMeans as $paymentMean) { - if ($storedMethodId === ($paymentMean->getRaw()['stored_method_id'] ?? null)) { + if ($paymentMean->getValue('stored_method_id') === $storedMethodId) { return $paymentMean; } } @@ -107,7 +107,7 @@ public function fetchByStoredMethodUmbrellaId(string $storedMethodId): ?PaymentM public function fetchById(int $id): ?PaymentMean { foreach ($this->paymentMeans as $paymentMean) { - if ($id === $paymentMean->getId()) { + if ($paymentMean->getId() === $id) { return $paymentMean; } } diff --git a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php index 1c1bd5c3..4dfb1640 100644 --- a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php @@ -44,7 +44,7 @@ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollec $paymentMethodOptions['value'] ); - $umbrellaPaymentMean = $paymentMeans->fetchUmbrellaMean(); + $umbrellaPaymentMean = $paymentMeans->fetchStoredMethodUmbrellaPaymentMean(); if (null === $umbrellaPaymentMean) { throw UmbrellaPaymentMeanNotFoundException::missingUmbrellaPaymentMean(); } diff --git a/Enricher/Payment/PaymentMethodEnricher.php b/Enricher/Payment/PaymentMethodEnricher.php index 91b78335..f80dc522 100644 --- a/Enricher/Payment/PaymentMethodEnricher.php +++ b/Enricher/Payment/PaymentMethodEnricher.php @@ -34,20 +34,8 @@ public function __invoke(array $shopwareMethod, PaymentMethod $paymentMethod): a 'isAdyenPaymentMethod' => true, 'adyenType' => $paymentMethod->adyenType()->type(), 'metadata' => $paymentMethod->rawData(), - 'stored_method_umbrella_id' => $paymentMethod->isStoredPayment() ? sprintf( - '%s_%s', - $shopwareMethod['id'], - $paymentMethod->getStoredPaymentMethodId() - ) : null, - 'stored_method_id' => $paymentMethod->isStoredPayment() ? $paymentMethod->getStoredPaymentMethodId() : null, ], - $paymentMethod->isStoredPayment() ? [ - 'description' => $paymentMethod->getValue('name'), - 'source' => SourceType::adyen()->getType(), - 'attribute' => new Attribute([ - AdyenPayment::ADYEN_STORED_METHOD_ID => $paymentMethod->getStoredPaymentMethodId(), - ]), - ] : [] + $this->enrichStoredPaymentMethodData($shopwareMethod, $paymentMethod) ); } @@ -70,4 +58,25 @@ private function enrichAdditionalDescription(PaymentMethod $adyenMethod): string $adyenMethod->getValue('lastFour', '') ); } + + private function enrichStoredPaymentMethodData(array $shopwareMethod, PaymentMethod $paymentMethod): array + { + if (!$paymentMethod->isStoredPayment()) { + return []; + } + + return [ + 'stored_method_umbrella_id' => sprintf( + '%s_%s', + $shopwareMethod['id'], + $paymentMethod->getStoredPaymentMethodId() + ), + 'stored_method_id' => $paymentMethod->getStoredPaymentMethodId(), + 'description' => $paymentMethod->getValue('name'), + 'source' => SourceType::adyen()->getType(), + 'attribute' => new Attribute([ + AdyenPayment::ADYEN_STORED_METHOD_ID => $paymentMethod->getStoredPaymentMethodId(), + ]), + ]; + } } diff --git a/Resources/frontend/js/jquery.adyen-payment-selection.js b/Resources/frontend/js/jquery.adyen-payment-selection.js index 4972e315..f76f1102 100644 --- a/Resources/frontend/js/jquery.adyen-payment-selection.js +++ b/Resources/frontend/js/jquery.adyen-payment-selection.js @@ -122,17 +122,17 @@ }, onPaymentFormSubmit: function (e) { var me = this; - let $formSubmit = $(me.opts.paymentMethodFormSubmitSelector); + var $formSubmit = $(me.opts.paymentMethodFormSubmitSelector); if ($formSubmit.hasClass('is--disabled')) { e.preventDefault(); return false; } - var $paymentElement = $('.payment--method [name="payment"]:checked')[0]; + var $paymentElement = $('#' + me.selectedPaymentElementId)[0]; var paymentMethod = this.getPaymentMethodById($paymentElement.value); if(paymentMethod.isStoredPayment){ - var $storedMethodElement = $(''); - $storedMethodElement.val(paymentMethod.stored_method_id); - $formSubmit.append($storedMethodElement); + $formSubmit.append( + $('') + ); } $paymentElement.value = paymentMethod.id; }, diff --git a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php index 7fec04aa..e0e78cc4 100644 --- a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php +++ b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php @@ -4,6 +4,7 @@ namespace AdyenPayment\Subscriber\Checkout; +use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProviderInterface; use Enlight\Event\SubscriberInterface; @@ -38,7 +39,7 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } - $storedMethodId = $this->session->get('storedMethodId'); + $storedMethodId = $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); if (null === $storedMethodId) { return; } @@ -48,7 +49,7 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()) ); - $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodUmbrellaId($storedMethodId); + $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodId($storedMethodId); if (null === $paymentMean) { return; } @@ -56,6 +57,6 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void $userData = $subject->View()->getAssign('sUserData'); $userData['additional']['payment'] = $paymentMean->getRaw(); $subject->View()->assign('sUserData', $userData); - $subject->View()->assign('sFormData', ['payment' => $paymentMean->getRaw()['stored_method_umbrella_id']]); + $subject->View()->assign('sFormData', ['payment' => $paymentMean->getValue('stored_method_umbrella_id')]); } } diff --git a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php index e1c22822..6bb47dab 100644 --- a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php +++ b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php @@ -4,8 +4,10 @@ namespace AdyenPayment\Subscriber\Checkout; +use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProviderInterface; +use AdyenPayment\Models\Payment\PaymentMean; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; @@ -37,23 +39,23 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } - $storedMethodId = $this->session->get('storedMethodId'); - $userData = $subject->View()->getAssign('sUserData'); - $paymentMeanId = $userData['additional']['payment']['id'] ?? null; + $paymentMean = null; - if (null === $storedMethodId && null === $paymentMeanId) { - return; + $storedMethodId = $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); + if (null !== $storedMethodId) { + $admin = Shopware()->Modules()->Admin(); + $enrichedPaymentMeans = PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()); + $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodId($storedMethodId); } - $admin = Shopware()->Modules()->Admin(); - $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( - PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()) - ); - - $paymentMean = null === $storedMethodId - ? $enrichedPaymentMeans->fetchById((int) $paymentMeanId) - : $enrichedPaymentMeans->fetchByStoredMethodUmbrellaId($storedMethodId); + $userData = $subject->View()->getAssign('sUserData'); if (null === $paymentMean) { + $paymentMean = PaymentMean::createFromShopwareArray($userData['additional']['payment'] ?? []); + $paymentMeans = ($this->enrichedPaymentMeanProvider)(new PaymentMeanCollection($paymentMean)); + $paymentMean = iterator_to_array($paymentMeans->getIterator())[0]; + } + + if (!$paymentMean->getId()) { return; } diff --git a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php index 9b801ee4..dbe0211b 100644 --- a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php +++ b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php @@ -4,6 +4,7 @@ namespace AdyenPayment\Subscriber\Checkout; +use AdyenPayment\AdyenPayment; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; @@ -30,9 +31,11 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void $actionName = $subject->Request()->getActionName(); $isShippingPaymentUpdate = 'shippingPayment' === $actionName && $subject->Request()->getParam('isXHR'); $isSaveShippingPayment = 'saveShippingPayment' === $actionName; - $storedMethodId = $subject->Request()->getParam('storedMethodId'); - if (null !== $storedMethodId && ($isShippingPaymentUpdate || $isSaveShippingPayment)) { - $this->session->set('storedMethodId', $storedMethodId); + if ($isShippingPaymentUpdate || $isSaveShippingPayment) { + $storedMethodId = $subject->Request()->getParam(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); + null !== $storedMethodId + ? $this->session->set(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId) + : $this->session->remove(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); } } } From a92f59f22ea9050ac0bb7887f860fae9342bd059 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 12 Jan 2022 11:19:35 +0100 Subject: [PATCH 031/136] ASW-377 - Stored Method ID save and CR fixes --- Enricher/Payment/PaymentMethodEnricher.php | 7 +-- Resources/services/subscribers.xml | 5 +- .../EnrichUmbrellaPaymentMeanSubscriber.php | 17 ++---- .../EnrichUserAdditionalPaymentSubscriber.php | 5 +- .../PersistStoredMethodIdSubscriber.php | 16 +++--- Subscriber/OrderStoredMethodIdSubscriber.php | 52 +++++++++++++++++++ 6 files changed, 75 insertions(+), 27 deletions(-) create mode 100644 Subscriber/OrderStoredMethodIdSubscriber.php diff --git a/Enricher/Payment/PaymentMethodEnricher.php b/Enricher/Payment/PaymentMethodEnricher.php index f80dc522..57805705 100644 --- a/Enricher/Payment/PaymentMethodEnricher.php +++ b/Enricher/Payment/PaymentMethodEnricher.php @@ -65,6 +65,9 @@ private function enrichStoredPaymentMethodData(array $shopwareMethod, PaymentMet return []; } + $attribute = $shopwareMethod['attribute'] ?? new Attribute(); + $attribute->set(AdyenPayment::ADYEN_STORED_METHOD_ID, $paymentMethod->getStoredPaymentMethodId()); + return [ 'stored_method_umbrella_id' => sprintf( '%s_%s', @@ -74,9 +77,7 @@ private function enrichStoredPaymentMethodData(array $shopwareMethod, PaymentMet 'stored_method_id' => $paymentMethod->getStoredPaymentMethodId(), 'description' => $paymentMethod->getValue('name'), 'source' => SourceType::adyen()->getType(), - 'attribute' => new Attribute([ - AdyenPayment::ADYEN_STORED_METHOD_ID => $paymentMethod->getStoredPaymentMethodId(), - ]), + 'attribute' => $attribute, ]; } } diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index 8d5244c6..3e62178d 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -53,6 +53,10 @@ + + + + @@ -95,7 +99,6 @@ - diff --git a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php index e0e78cc4..9f1782b5 100644 --- a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php +++ b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php @@ -6,28 +6,21 @@ use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; -use AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProviderInterface; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; final class EnrichUmbrellaPaymentMeanSubscriber implements SubscriberInterface { - private EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider; private Enlight_Components_Session_Namespace $session; - public function __construct( - EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider, - Enlight_Components_Session_Namespace $session - ) { - $this->enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + public function __construct(Enlight_Components_Session_Namespace $session) + { $this->session = $session; } public static function getSubscribedEvents(): array { - return [ - 'Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke', - ]; + return ['Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke']; } public function __invoke(\Enlight_Controller_ActionEventArgs $args): void @@ -45,9 +38,7 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void } $admin = Shopware()->Modules()->Admin(); - $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( - PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()) - ); + $enrichedPaymentMeans = PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()); $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodId($storedMethodId); if (null === $paymentMean) { diff --git a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php index 6bb47dab..8396f9e6 100644 --- a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php +++ b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php @@ -43,8 +43,9 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void $storedMethodId = $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); if (null !== $storedMethodId) { - $admin = Shopware()->Modules()->Admin(); - $enrichedPaymentMeans = PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()); + $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( + PaymentMeanCollection::createFromShopwareArray(Shopware()->Modules()->Admin()->sGetPaymentMeans()) + ); $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodId($storedMethodId); } diff --git a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php index dbe0211b..768a29e4 100644 --- a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php +++ b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php @@ -12,9 +12,8 @@ final class PersistStoredMethodIdSubscriber implements SubscriberInterface { private Enlight_Components_Session_Namespace $session; - public function __construct( - Enlight_Components_Session_Namespace $session - ) { + public function __construct(Enlight_Components_Session_Namespace $session) + { $this->session = $session; } @@ -29,13 +28,14 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void { $subject = $args->getSubject(); $actionName = $subject->Request()->getActionName(); + $isShippingPaymentUpdate = 'shippingPayment' === $actionName && $subject->Request()->getParam('isXHR'); $isSaveShippingPayment = 'saveShippingPayment' === $actionName; - if ($isShippingPaymentUpdate || $isSaveShippingPayment) { - $storedMethodId = $subject->Request()->getParam(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); - null !== $storedMethodId - ? $this->session->set(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId) - : $this->session->remove(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); + if (!$isShippingPaymentUpdate && !$isSaveShippingPayment) { + return; } + + $storedMethodId = $subject->Request()->getParam(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); + $this->session->set(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId); } } diff --git a/Subscriber/OrderStoredMethodIdSubscriber.php b/Subscriber/OrderStoredMethodIdSubscriber.php new file mode 100644 index 00000000..40946d71 --- /dev/null +++ b/Subscriber/OrderStoredMethodIdSubscriber.php @@ -0,0 +1,52 @@ +modelManager = $modelManager; + $this->paymentInfoRepository = $this->modelManager->getRepository(PaymentInfo::class); + } + + public static function getSubscribedEvents() + { + return ['Shopware_Modules_Order_SaveOrder_ProcessDetails' => 'persistPaymentInfoStoredMethodId']; + } + + public function persistPaymentInfoStoredMethodId(Enlight_Event_EventArgs $args) + { + $paymentInfoId = Shopware()->Session()->get(AdyenPayment::SESSION_ADYEN_PAYMENT_INFO_ID); + $storedMethodId = Shopware()->Session()->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); + + if (null === $paymentInfoId) { + return $args->getReturn(); + } + + /** @var PaymentInfo $paymentInfo */ + $paymentInfo = $this->paymentInfoRepository->findOneBy([ + 'id' => $paymentInfoId, + ]); + + if ($paymentInfo) { + $paymentInfo->setStoredMethodId($storedMethodId); + $this->modelManager->persist($paymentInfo); + $this->modelManager->flush($paymentInfo); + } + + return $args->getReturn(); + } +} From 7bbdc08fcf8e37a8931e50461f899875d34cf2c6 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 12 Jan 2022 12:16:07 +0100 Subject: [PATCH 032/136] ASW-377 - PaymentMeanCollection tests --- Collection/Payment/PaymentMeanCollection.php | 16 -- .../Payment/PaymentMeanCollectionTest.php | 160 ++++++++++++++++++ 2 files changed, 160 insertions(+), 16 deletions(-) create mode 100644 tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php diff --git a/Collection/Payment/PaymentMeanCollection.php b/Collection/Payment/PaymentMeanCollection.php index c2ae15f4..6dd87029 100644 --- a/Collection/Payment/PaymentMeanCollection.php +++ b/Collection/Payment/PaymentMeanCollection.php @@ -77,11 +77,6 @@ public function filterExcludeHidden(): self )); } - public function filterByAdyenSource(): self - { - return $this->filterBySource(SourceType::adyen()); - } - public function fetchStoredMethodUmbrellaPaymentMean(): ?PaymentMean { foreach ($this->paymentMeans as $paymentMean) { @@ -104,17 +99,6 @@ public function fetchByStoredMethodId(string $storedMethodId): ?PaymentMean return null; } - public function fetchById(int $id): ?PaymentMean - { - foreach ($this->paymentMeans as $paymentMean) { - if ($paymentMean->getId() === $id) { - return $paymentMean; - } - } - - return null; - } - public function toShopwareArray(): array { return array_reduce($this->paymentMeans, static function(array $payload, PaymentMean $paymentMean): array { diff --git a/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php new file mode 100644 index 00000000..dbefc2c6 --- /dev/null +++ b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php @@ -0,0 +1,160 @@ + SourceType::adyen()->getType()]]); + + self::assertInstanceOf(\Countable::class, $result); + self::assertCount(1, $result); + } + + /** @test */ + public function it_can_map_with_a_callback(): void + { + $expectedMethod = [true]; + $filteredSource = SourceType::adyen(); + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType()], + ['source' => '1'], + ]); + + $result = $collection->map(static function(PaymentMean $payment) use ($filteredSource) { + return $payment->getSource()->equals($filteredSource); + }); + + self::assertEquals($expectedMethod, $result); + } + + /** @test */ + public function it_can_filter_by_source(): void + { + $filteredSource = SourceType::adyen(); + $expected = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType()], + ]); + + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType()], + ['source' => '1'], + ]); + + $result = $collection->filterBySource($filteredSource); + + self::assertEquals($expected, $result); + } + + /** @test */ + public function it_can_exclude_adyen(): void + { + $filteredSource = SourceType::adyen(); + $expected = PaymentMeanCollection::createFromShopwareArray([ + ['source' => '1'], + ]); + + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType()], + ['source' => '1'], + ]); + + $result = $collection->filterExcludeAdyen(); + + self::assertEquals($expected, $result); + } + + /** @test */ + public function it_can_exclude_hidden(): void + { + $filteredSource = SourceType::adyen(); + $expected = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType()], + ['source' => '1'], + ]); + + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType(), 'hide' => true], + ['source' => $filteredSource->getType()], + ['source' => '1'], + ['source' => '1', 'hide' => true], + ]); + + $result = $collection->filterExcludeHidden(); + + self::assertEquals($expected, $result); + } + + /** @test */ + public function it_can_fetch_umbrella_payment_if_available(): void + { + $filteredSource = SourceType::adyen(); + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType(), 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE], + ['source' => '1'], + ]); + + $result = $collection->fetchStoredMethodUmbrellaPaymentMean(); + + self::assertInstanceOf(PaymentMean::class, $result); + self::assertEquals(AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, $result->getValue('name')); + } + + /** @test */ + public function it_will_return_null_on_fetch_umbrella_if_payment_not_available(): void + { + $filteredSource = SourceType::adyen(); + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType()], + ['source' => '1'], + ]); + + $result = $collection->fetchStoredMethodUmbrellaPaymentMean(); + + self::assertNull($result); + } + + /** @test */ + public function it_can_fetch_a_payment_by_stored_method_id(): void + { + $filteredSource = SourceType::adyen(); + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType()], + ['source' => '1', 'stored_method_id' => $testId = 'test123'], + ]); + + $result = $collection->fetchByStoredMethodId($testId); + + self::assertInstanceOf(PaymentMean::class, $result); + self::assertEquals(1, $result->getSource()->getType()); + } + + /** @test */ + public function it_will_return_null_on_fetch_by_stored_method_id_if_payment_not_available(): void + { + $filteredSource = SourceType::adyen(); + $paymentData = ['id' => '123', 'source' => $filteredSource->getType()]; + $expected = [$paymentData['id'] => $paymentData]; + $collection = PaymentMeanCollection::createFromShopwareArray([$paymentData]); + + $result = $collection->toShopwareArray(); + + self::assertEquals($expected, $result); + } +} From 5d835227bc50034f34abc215b994942c73211c20 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 12 Jan 2022 12:51:15 +0100 Subject: [PATCH 033/136] ASW-377 - EnrichedPaymentMeanProviderTest updated --- .../EnrichedPaymentMeanProviderTest.php | 61 ++++++++++++++++--- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php index d9b483bf..f0ef9957 100644 --- a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php +++ b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php @@ -4,6 +4,7 @@ namespace AdyenPayment\Tests\Unit\Components\Adyen\PaymentMethod; +use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Collection\Payment\PaymentMethodCollection; use AdyenPayment\Components\Adyen\Builder\PaymentMethodOptionsBuilderInterface; @@ -11,6 +12,7 @@ use AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProviderInterface; use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use AdyenPayment\Enricher\Payment\PaymentMethodEnricherInterface; +use AdyenPayment\Exceptions\UmbrellaPaymentMeanNotFoundException; use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMean; use AdyenPayment\Models\Payment\PaymentMethod; @@ -20,7 +22,7 @@ use Prophecy\Prophecy\ObjectProphecy; use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; -class EnrichedPaymentMeanProviderTest extends TestCase +final class EnrichedPaymentMeanProviderTest extends TestCase { use ProphecyTrait; @@ -42,8 +44,6 @@ class EnrichedPaymentMeanProviderTest extends TestCase protected function setUp(): void { - // @TODO - ASW-377: refactor test to match new code on the EnrichedPaymentMeanProvider class. - $this->markTestSkipped('@TODO - ASW-377'); $this->paymentMethodService = $this->prophesize(PaymentMethodServiceInterface::class); $this->paymentMethodOptionsBuilder = $this->prophesize(PaymentMethodOptionsBuilderInterface::class); $this->paymentMethodEnricher = $this->prophesize(PaymentMethodEnricherInterface::class); @@ -85,6 +85,36 @@ public function it_does_not_enrich_on_empty_cart_value_and_excludes_adyen_method $this->assertSame($paymentMeanOne, iterator_to_array($result)[0]); } + /** @test */ + public function it_throws_an_exception_on_missing_umbrella_payment(): void + { + $adyenIdentifier = sprintf('%s_%s', $adyenType = 'non', $adyenName = 'adyen'); + $paymentMeans = new PaymentMeanCollection( + $paymentMeanOne = PaymentMean::createFromShopwareArray([ + 'id' => 1, + 'source' => SourceType::shopwareDefault()->getType(), + ]), + ); + + // filled with a matching identifier, to catch if the early returns fails + $adyenPaymentMethods = new PaymentMethodCollection( + PaymentMethod::fromRaw(['type' => $adyenType])->withCode($adyenName), + ); + + $this->paymentMethodOptionsBuilder->__invoke()->willReturn([ + 'countryCode' => $countryCode = 'BE', + 'currency' => $currency = 'EUR', + 'value' => $value = 17.7, + ]); + $this->paymentMethodService->getPaymentMethods($countryCode, $currency, $value) + ->willReturn($adyenPaymentMethods); + $this->paymentMethodEnricher->__invoke(Argument::cetera())->shouldNotBeCalled(); + + $this->expectException(UmbrellaPaymentMeanNotFoundException::class); + + $result = $this->provider->__invoke($paymentMeans); + } + /** @test */ public function it_does_not_enrich_non_adyen_methods(): void { @@ -92,6 +122,7 @@ public function it_does_not_enrich_non_adyen_methods(): void $paymentMeans = new PaymentMeanCollection( $paymentMean = PaymentMean::createFromShopwareArray([ 'id' => 17, + 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, 'source' => SourceType::shopwareDefault()->getType(), 'attribute' => new Attribute([ 'adyen_type' => $adyenIdentifier, @@ -126,6 +157,7 @@ public function it_does_not_enrich_and_removes_payment_means_without_attribute() $paymentMeans = new PaymentMeanCollection( $paymentMeanOne = PaymentMean::createFromShopwareArray([ 'id' => 19, + 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, 'source' => SourceType::shopwareDefault()->getType(), ]), $paymentMeanTwo = PaymentMean::createFromShopwareArray([ @@ -155,6 +187,7 @@ public function it_does_not_enrich_payment_means_with_attribute_null_values(): v $paymentMeans = new PaymentMeanCollection( $paymentMean = PaymentMean::createFromShopwareArray([ 'id' => 9, + 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, 'source' => SourceType::adyen()->getType(), 'attribute' => new Attribute([ 'adyen_type' => null, @@ -183,6 +216,7 @@ public function it_removes_adyen_payment_means_without_matching_adyen_payment_me $paymentMeans = new PaymentMeanCollection( $paymentMean = PaymentMean::createFromShopwareArray([ 'id' => 25, + 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, 'source' => SourceType::adyen()->getType(), 'attribute' => new Attribute([ 'adyen_type' => 'non_matching_adyen_identifier', @@ -218,15 +252,20 @@ public function it_enriches_adyen_payment_methods(): void 'adyen_stored_method_id' => null, ]), ]), + $umbrellaMean = PaymentMean::createFromShopwareArray([ + 'id' => 25, + 'source' => SourceType::adyen()->getType(), + 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, + ]), ); $adyenPaymentMethods = new PaymentMethodCollection( $paymentMethod = PaymentMethod::fromRaw([ 'type' => $adyenType, ])->withCode($adyenName), - $storedPaymentMethod = PaymentMethod::fromRaw([ - 'id' => 'adyen-stored-payment-method-id', - 'type' => 'scheme', + $storedPaymentMethod = PaymentMethod::fromRaw($storedRaw = [ + 'id' => $storedMethodId = 'adyen-stored-payment-method-id', + 'type' => $schemaType = 'scheme', ]), ); @@ -245,9 +284,17 @@ public function it_enriches_adyen_payment_methods(): void 'adyenType' => $adyenType, ]); + $this->paymentMethodEnricher->__invoke($umbrellaMean->getRaw(), $storedPaymentMethod)->willReturn($storedRawEnriched = [ + 'id' => $storedMethodId, + 'adyenType' => $schemaType, + 'source' => $source, + ]); + $result = $this->provider->__invoke($paymentMeans); + $this->assertInstanceOf(PaymentMeanCollection::class, $result); - $this->assertCount(1, $result); + $this->assertCount(2, $result); $this->assertEquals($rawEnriched, iterator_to_array($result)[0]->getRaw()); + $this->assertEquals($storedRawEnriched, iterator_to_array($result)[1]->getRaw()); } } From 1d0998423d750b7c20b832f416d213a22e1544ff Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 13 Jan 2022 08:23:49 +0100 Subject: [PATCH 034/136] ASW-377 - PaymentMethodEnricher unit test --- .../Payment/PaymentMethodEnricherTest.php | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php diff --git a/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php b/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php new file mode 100644 index 00000000..3c9570f5 --- /dev/null +++ b/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php @@ -0,0 +1,118 @@ +snippets = $this->prophesize(Shopware_Components_Snippet_Manager::class); + $this->imageLogoProvider = $this->prophesize(ImageLogoProviderInterface::class); + + $this->paymentMethodEnricher = new PaymentMethodEnricher( + $this->snippets->reveal(), + $this->imageLogoProvider->reveal() + ); + } + + /** @test */ + public function it_is_a_payment_method_enricher(): void + { + $this->assertInstanceOf(PaymentMethodEnricherInterface::class, $this->paymentMethodEnricher); + } + + /** @test */ + public function it_will_enrich_a_payment_method_without_stored_method_data(): void + { + $shopwareMethod = [ + 'id' => 'shopware-method-id', + 'additionaldescription' => '', + 'image' => '', + ]; + $paymentMethod = PaymentMethod::fromRaw($rawData = [ + 'code' => 'test_method', + 'type' => 'test_type', + ]); + $snippetsNamespace = $this->prophesize(\Enlight_Components_Snippet_Namespace::class); + $snippetsNamespace->get($paymentMethod->adyenType()->type())->willReturn($description = 'Adyen Method'); + $this->snippets->getNamespace('adyen/method/description')->willReturn($snippetsNamespace); + $this->imageLogoProvider->provideByType($paymentMethod->adyenType()->type())->willReturn($image = 'image'); + + $result = ($this->paymentMethodEnricher)($shopwareMethod, $paymentMethod); + + $expected = [ + 'id' => 'shopware-method-id', + 'additionaldescription' => $description, + 'image' => $image, + 'enriched' => true, + 'isStoredPayment' => false, + 'isAdyenPaymentMethod' => true, + 'adyenType' => $paymentMethod->adyenType()->type(), + 'metadata' => $rawData, + ]; + + self::assertEquals($expected, $result); + } + + /** @test */ + public function it_will_enrich_a_payment_method_with_stored_method_data(): void + { + $shopwareMethod = ['id' => $shopwareMethodId = 'shopware-method-id']; + $paymentMethod = PaymentMethod::fromRaw($rawData = [ + 'id' => $storedMethodId = 'stored_method_id', + 'name' => $storedMethodName = 'stored method name', + 'code' => 'test_method', + 'type' => 'test_type', + 'lastFour' => $lastFour = '1234', + ]); + $snippetsNamespace = $this->prophesize(\Enlight_Components_Snippet_Namespace::class); + $snippetsNamespace->get($paymentMethod->adyenType()->type())->willReturn($description = 'Stored Method'); + $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); + $this->imageLogoProvider->provideByType($paymentMethod->adyenType()->type())->willReturn($image = 'image'); + + $result = ($this->paymentMethodEnricher)($shopwareMethod, $paymentMethod); + + $expected = [ + 'id' => 'shopware-method-id', + 'additionaldescription' => sprintf('%s%s: %s', $description.' ', $text, $lastFour), + 'image' => $image, + 'enriched' => true, + 'isStoredPayment' => true, + 'isAdyenPaymentMethod' => true, + 'adyenType' => $paymentMethod->adyenType()->type(), + 'metadata' => $rawData, + 'stored_method_umbrella_id' => sprintf('%s_%s', $shopwareMethodId, $storedMethodId), + 'stored_method_id' => $storedMethodId, + 'description' => $storedMethodName, + 'source' => SourceType::adyen()->getType(), + 'attribute' => new Attribute([AdyenPayment::ADYEN_STORED_METHOD_ID => $storedMethodId]), + ]; + + self::assertEquals($expected, $result); + } +} From b4398c8263e5a39290cf6bc3dd1b54eb75ce032a Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 13 Jan 2022 10:27:18 +0100 Subject: [PATCH 035/136] ASW-377 - Admin get payments refactor and unit tests --- Resources/services/shopware.xml | 2 +- Resources/services/subscribers.xml | 1 + Shopware/Provider/PaymentMeansProvider.php | 13 ++ .../PaymentMeansProviderInterface.php | 10 ++ .../EnrichUmbrellaPaymentMeanSubscriber.php | 16 ++- ...nrichUmbrellaPaymentMeanSubscriberTest.php | 119 ++++++++++++++++++ 6 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 Shopware/Provider/PaymentMeansProvider.php create mode 100644 Shopware/Provider/PaymentMeansProviderInterface.php create mode 100644 tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php diff --git a/Resources/services/shopware.xml b/Resources/services/shopware.xml index 7e903c46..67d668cd 100644 --- a/Resources/services/shopware.xml +++ b/Resources/services/shopware.xml @@ -6,6 +6,6 @@ + - diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index 3e62178d..acf5b546 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -100,6 +100,7 @@ + diff --git a/Shopware/Provider/PaymentMeansProvider.php b/Shopware/Provider/PaymentMeansProvider.php new file mode 100644 index 00000000..745e2e81 --- /dev/null +++ b/Shopware/Provider/PaymentMeansProvider.php @@ -0,0 +1,13 @@ +Modules()->Admin()->sGetPaymentMeans(); + } +} diff --git a/Shopware/Provider/PaymentMeansProviderInterface.php b/Shopware/Provider/PaymentMeansProviderInterface.php new file mode 100644 index 00000000..67848b21 --- /dev/null +++ b/Shopware/Provider/PaymentMeansProviderInterface.php @@ -0,0 +1,10 @@ +session = $session; + $this->paymentMeansProvider = $paymentMeansProvider; } public static function getSubscribedEvents(): array @@ -26,8 +31,8 @@ public static function getSubscribedEvents(): array public function __invoke(\Enlight_Controller_ActionEventArgs $args): void { $subject = $args->getSubject(); - $actionName = $subject->Request()->getActionName(); - $isShippingPaymentView = 'shippingPayment' === $actionName && !$subject->Request()->getParam('isXHR'); + $actionName = $args->getRequest()->getActionName(); + $isShippingPaymentView = 'shippingPayment' === $actionName && !$args->getRequest()->getParam('isXHR'); if (!$isShippingPaymentView) { return; } @@ -37,8 +42,7 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } - $admin = Shopware()->Modules()->Admin(); - $enrichedPaymentMeans = PaymentMeanCollection::createFromShopwareArray($admin->sGetPaymentMeans()); + $enrichedPaymentMeans = PaymentMeanCollection::createFromShopwareArray(($this->paymentMeansProvider)()); $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodId($storedMethodId); if (null === $paymentMean) { diff --git a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php new file mode 100644 index 00000000..506e0600 --- /dev/null +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -0,0 +1,119 @@ +session = $this->prophesize(Enlight_Components_Session_Namespace::class); + $this->paymentMeansProvider = $this->prophesize(PaymentMeansProviderInterface::class); + $this->subscriber = new EnrichUmbrellaPaymentMeanSubscriber( + $this->session->reveal(), + $this->paymentMeansProvider->reveal() + ); + } + + /** @test */ + public function it_is_a_subscriber(): void + { + self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); + } + + /** @test */ + public function it_subscribe_to_the_proper_events(): void + { + self::assertEquals( + ['Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke'], + EnrichUmbrellaPaymentMeanSubscriber::getSubscribedEvents() + ); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_action_name(): void + { + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_xhr_request(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = ['data' => 'view-data']); + $eventArgs->getRequest()->setParam('isXHR', true); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_missing_session_stored_method_id(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = ['data' => 'view-data']); + $eventArgs->getRequest()->setParam('isXHR', false); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_missing_payment_mean_for_stored_method(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = ['data' => 'view-data']); + $eventArgs->getRequest()->setParam('isXHR', false); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn($storedMethodId = 'method-id'); + $this->paymentMeansProvider->__invoke()->willReturn([]); + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_will_enrich_the_payment_mean_for_stored_method(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = [ + 'sUserData' => ['additional' => ['payment' => ['not-enriched-payment-data']]], + 'sFormData' => [], + ]); + $eventArgs->getRequest()->setParam('isXHR', false); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn($storedMethodId = 'method-id'); + $this->paymentMeansProvider->__invoke()->willReturn([$paymentMeanRaw = [ + 'source' => 123, + 'adyenType' => 'test', + 'stored_method_id' => $storedMethodId, + 'stored_method_umbrella_id' => $umbrellaId = 'umbrella-id', + ]]); + + $this->subscriber->__invoke($eventArgs); + + $expected = [ + 'sUserData' => ['additional' => ['payment' => $paymentMeanRaw]], + 'sFormData' => ['payment' => $umbrellaId], + ]; + + $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + } +} From 5a13506fab9b6189c41647f85cce24039f7d014b Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 13 Jan 2022 11:34:31 +0100 Subject: [PATCH 036/136] ASW-377 - Fixed issue and unit tests --- Collection/Payment/PaymentMeanCollection.php | 11 ++ Resources/services/subscribers.xml | 1 + .../EnrichUserAdditionalPaymentSubscriber.php | 34 ++-- .../Payment/PaymentMeanCollectionTest.php | 15 ++ ...ichUserAdditionalPaymentSubscriberTest.php | 166 ++++++++++++++++++ 5 files changed, 211 insertions(+), 16 deletions(-) create mode 100644 tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php diff --git a/Collection/Payment/PaymentMeanCollection.php b/Collection/Payment/PaymentMeanCollection.php index 6dd87029..9aab755e 100644 --- a/Collection/Payment/PaymentMeanCollection.php +++ b/Collection/Payment/PaymentMeanCollection.php @@ -88,6 +88,17 @@ public function fetchStoredMethodUmbrellaPaymentMean(): ?PaymentMean return null; } + public function fetchById(int $paymentId): ?PaymentMean + { + foreach ($this->paymentMeans as $paymentMean) { + if ($paymentMean->getId() === $paymentId) { + return $paymentMean; + } + } + + return null; + } + public function fetchByStoredMethodId(string $storedMethodId): ?PaymentMean { foreach ($this->paymentMeans as $paymentMean) { diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index acf5b546..b62b714f 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -95,6 +95,7 @@ + diff --git a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php index 8396f9e6..eb157adc 100644 --- a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php +++ b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php @@ -7,20 +7,23 @@ use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProviderInterface; -use AdyenPayment\Models\Payment\PaymentMean; +use AdyenPayment\Shopware\Provider\PaymentMeansProviderInterface; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; final class EnrichUserAdditionalPaymentSubscriber implements SubscriberInterface { private EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider; + private PaymentMeansProviderInterface $paymentMeansProvider; private Enlight_Components_Session_Namespace $session; public function __construct( EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider, + PaymentMeansProviderInterface $paymentMeansProvider, Enlight_Components_Session_Namespace $session ) { $this->enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + $this->paymentMeansProvider = $paymentMeansProvider; $this->session = $session; } @@ -35,28 +38,27 @@ public static function getSubscribedEvents(): array public function __invoke(\Enlight_Controller_ActionEventArgs $args): void { $subject = $args->getSubject(); - if ('confirm' !== $subject->Request()->getActionName()) { + if ('confirm' !== $args->getRequest()->getActionName()) { return; } - $paymentMean = null; - $storedMethodId = $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); - if (null !== $storedMethodId) { - $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( - PaymentMeanCollection::createFromShopwareArray(Shopware()->Modules()->Admin()->sGetPaymentMeans()) - ); - $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodId($storedMethodId); - } - $userData = $subject->View()->getAssign('sUserData'); - if (null === $paymentMean) { - $paymentMean = PaymentMean::createFromShopwareArray($userData['additional']['payment'] ?? []); - $paymentMeans = ($this->enrichedPaymentMeanProvider)(new PaymentMeanCollection($paymentMean)); - $paymentMean = iterator_to_array($paymentMeans->getIterator())[0]; + $paymentMeanId = $userData['additional']['payment']['id'] ?? null; + + if (null === $storedMethodId && null === $paymentMeanId) { + return; } - if (!$paymentMean->getId()) { + $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( + PaymentMeanCollection::createFromShopwareArray(($this->paymentMeansProvider)()) + ); + + $paymentMean = null === $storedMethodId + ? $enrichedPaymentMeans->fetchById((int) $paymentMeanId) + : $enrichedPaymentMeans->fetchByStoredMethodId($storedMethodId); + + if (null === $paymentMean) { return; } diff --git a/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php index dbefc2c6..0aaa6461 100644 --- a/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php +++ b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php @@ -145,6 +145,21 @@ public function it_can_fetch_a_payment_by_stored_method_id(): void self::assertEquals(1, $result->getSource()->getType()); } + /** @test */ + public function it_can_fetch_a_payment_by_payment_id(): void + { + $filteredSource = SourceType::adyen(); + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['id' => $testId = 123, 'source' => $filteredSource->getType()], + ['' => '456', 'source' => '1'], + ]); + + $result = $collection->fetchById($testId); + + self::assertInstanceOf(PaymentMean::class, $result); + self::assertEquals(123, $result->getId()); + } + /** @test */ public function it_will_return_null_on_fetch_by_stored_method_id_if_payment_not_available(): void { diff --git a/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php new file mode 100644 index 00000000..aec923be --- /dev/null +++ b/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php @@ -0,0 +1,166 @@ +enrichedPaymentMeanProvider = $this->prophesize(EnrichedPaymentMeanProviderInterface::class); + $this->paymentMeansProvider = $this->prophesize(PaymentMeansProviderInterface::class); + $this->session = $this->prophesize(Enlight_Components_Session_Namespace::class); + $this->subscriber = new EnrichUserAdditionalPaymentSubscriber( + $this->enrichedPaymentMeanProvider->reveal(), + $this->paymentMeansProvider->reveal(), + $this->session->reveal() + ); + } + + /** @test */ + public function it_is_a_subscriber(): void + { + self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); + } + + /** @test */ + public function it_subscribe_to_the_proper_events(): void + { + self::assertEquals( + ['Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => ['__invoke', -99999]], + EnrichUserAdditionalPaymentSubscriber::getSubscribedEvents() + ); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_action_name(): void + { + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_missing_stored_method_id_and_payment_mean_id(): void + { + $eventArgs = $this->buildEventArgs('confirm', $viewData = ['sUserData' => []]); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_missing_payment_mean_for_stored_method_id(): void + { + $eventArgs = $this->buildEventArgs('confirm', $viewData = ['sUserData' => []]); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn('method-id'); + $this->paymentMeansProvider->__invoke()->willReturn($paymentMeansRaw = [[ + 'source' => 123, + 'adyenType' => 'test', + ]]); + + $paymentMeans = PaymentMeanCollection::createFromShopwareArray($paymentMeansRaw); + $this->enrichedPaymentMeanProvider->__invoke($paymentMeans)->willReturn($paymentMeans); + + $this->subscriber->__invoke($eventArgs); + + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_missing_payment_mean_for_payment_id(): void + { + $eventArgs = $this->buildEventArgs('confirm', $viewData = ['sUserData' => [ + 'additional' => ['payment' => ['id' => $paymentId = '123123']], + ]]); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); + $this->paymentMeansProvider->__invoke()->willReturn($paymentMeansRaw = [[ + 'source' => 123, + 'adyenType' => 'test', + ]]); + + $paymentMeans = PaymentMeanCollection::createFromShopwareArray($paymentMeansRaw); + $this->enrichedPaymentMeanProvider->__invoke($paymentMeans)->willReturn($paymentMeans); + + $this->subscriber->__invoke($eventArgs); + + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_will_update_the_view_with_payment_mean_for_stored_method_id(): void + { + $eventArgs = $this->buildEventArgs('confirm', $viewData = ['sUserData' => []]); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn($storedMethodId = 'method-id'); + $this->paymentMeansProvider->__invoke()->willReturn($paymentMeansRaw = [$paymentMeanRaw = [ + 'source' => 123, + 'adyenType' => 'test', + 'stored_method_id' => $storedMethodId, + ]]); + + $paymentMeans = PaymentMeanCollection::createFromShopwareArray($paymentMeansRaw); + $this->enrichedPaymentMeanProvider->__invoke($paymentMeans)->willReturn($paymentMeans); + + $this->subscriber->__invoke($eventArgs); + + $expected = [ + 'sUserData' => ['additional' => ['payment' => $paymentMeanRaw]], + ]; + + $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_will_update_the_view_with_payment_mean_for_payment_id(): void + { + $eventArgs = $this->buildEventArgs('confirm', $viewData = ['sUserData' => [ + 'additional' => ['payment' => ['id' => $paymentId = '123123']], + ]]); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); + $this->paymentMeansProvider->__invoke()->willReturn($paymentMeansRaw = [$paymentMeanRaw = [ + 'id' => $paymentId, + 'source' => 123, + 'adyenType' => 'test', + ]]); + + $paymentMeans = PaymentMeanCollection::createFromShopwareArray($paymentMeansRaw); + $this->enrichedPaymentMeanProvider->__invoke($paymentMeans)->willReturn($paymentMeans); + + $this->subscriber->__invoke($eventArgs); + + $expected = [ + 'sUserData' => ['additional' => ['payment' => $paymentMeanRaw]], + ]; + + $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + } +} From e585f76f41b33b452c2b69bff62f660b70dd709b Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 13 Jan 2022 11:50:29 +0100 Subject: [PATCH 037/136] ASW-377 - PersistStoredMethodIdSubscriber unit tests --- .../PersistStoredMethodIdSubscriber.php | 10 +-- .../PersistStoredMehtodIdSubscriberTest.php | 88 +++++++++++++++++++ 2 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php diff --git a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php index 768a29e4..204c7d13 100644 --- a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php +++ b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php @@ -19,23 +19,21 @@ public function __construct(Enlight_Components_Session_Namespace $session) public static function getSubscribedEvents(): array { - return [ - 'Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke', - ]; + return ['Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke']; } public function __invoke(\Enlight_Controller_ActionEventArgs $args): void { $subject = $args->getSubject(); - $actionName = $subject->Request()->getActionName(); + $actionName = $args->getRequest()->getActionName(); - $isShippingPaymentUpdate = 'shippingPayment' === $actionName && $subject->Request()->getParam('isXHR'); + $isShippingPaymentUpdate = 'shippingPayment' === $actionName && $args->getRequest()->getParam('isXHR'); $isSaveShippingPayment = 'saveShippingPayment' === $actionName; if (!$isShippingPaymentUpdate && !$isSaveShippingPayment) { return; } - $storedMethodId = $subject->Request()->getParam(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); + $storedMethodId = $args->getRequest()->getParam(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); $this->session->set(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId); } } diff --git a/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php b/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php new file mode 100644 index 00000000..f5316e02 --- /dev/null +++ b/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php @@ -0,0 +1,88 @@ +session = $this->prophesize(Enlight_Components_Session_Namespace::class); + $this->subscriber = new PersistStoredMethodIdSubscriber($this->session->reveal()); + } + + /** @test */ + public function it_is_a_subscriber(): void + { + self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); + } + + /** @test */ + public function it_subscribe_to_the_proper_events(): void + { + self::assertEquals( + ['Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => '__invoke'], + PersistStoredMethodIdSubscriber::getSubscribedEvents() + ); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_action_name(): void + { + $eventArgs = $this->buildEventArgs('', $viewData = []); + $eventArgs->getRequest()->setParam('isXHR', true); + + $this->subscriber->__invoke($eventArgs); + + $this->session->set(Argument::cetera())->shouldNotBeCalled(); + } + + /** @test */ + public function it_does_nothing_on_shipping_payment_non_xhr_request(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = []); + $eventArgs->getRequest()->setParam('isXHR', false); + + $this->subscriber->__invoke($eventArgs); + + $this->session->set(Argument::cetera())->shouldNotBeCalled(); + } + + /** @test */ + public function it_saves_in_session_the_stored_method_id_on_shipping_payment_xhr_request(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = []); + $eventArgs->getRequest()->setParam('isXHR', true); + $eventArgs->getRequest()->setParam(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId = '123123'); + + $this->session->set(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId)->shouldBeCalled(); + + $this->subscriber->__invoke($eventArgs); + } + + /** @test */ + public function it_saves_in_session_the_stored_method_id_on_save_shipping_payment(): void + { + $eventArgs = $this->buildEventArgs('saveShippingPayment', $viewData = []); + $eventArgs->getRequest()->setParam('isXHR', false); + $eventArgs->getRequest()->setParam(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId = '123123'); + + $this->session->set(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId)->shouldBeCalled(); + + $this->subscriber->__invoke($eventArgs); + } +} From ebd75da5e15f4da3a70b2b2b4d941db111b759b5 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 13 Jan 2022 12:11:30 +0100 Subject: [PATCH 038/136] ASW-377 - Fixed config --- Resources/services/shopware.xml | 2 +- Resources/services/subscribers.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/services/shopware.xml b/Resources/services/shopware.xml index 67d668cd..490cb309 100644 --- a/Resources/services/shopware.xml +++ b/Resources/services/shopware.xml @@ -6,6 +6,6 @@
- + diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index b62b714f..43c5a458 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -95,13 +95,13 @@ - + - + From b44bc3e2b3eaf20552845be1537d15a20bc31971 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 14 Jan 2022 10:18:47 +0100 Subject: [PATCH 039/136] ASW-435 - Attribute removed --- AdyenPayment.php | 12 ------------ Doctrine/Writer/PaymentAttributeWriter.php | 6 +----- Enricher/Payment/PaymentMethodEnricher.php | 6 ------ Models/Payment/PaymentMean.php | 6 +----- .../Payment/PaymentMethodCollectionTest.php | 4 ++-- .../EnrichedPaymentMeanProviderTest.php | 4 ---- .../Enricher/Payment/PaymentMethodEnricherTest.php | 3 --- tests/Unit/Models/Payment/PaymentMeanTest.php | 9 --------- 8 files changed, 4 insertions(+), 46 deletions(-) diff --git a/AdyenPayment.php b/AdyenPayment.php index 58e74888..654adcbb 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -32,7 +32,6 @@ final class AdyenPayment extends Plugin { public const NAME = 'AdyenPayment'; public const ADYEN_CODE = 'adyen_type'; - public const ADYEN_STORED_METHOD_ID = 'adyen_stored_method_id'; public const ADYEN_STORED_PAYMENT_UMBRELLA_CODE = 'adyen_stored_payment_umbrella'; public const SESSION_ADYEN_RESTRICT_EMAILS = 'adyenRestrictEmail'; public const SESSION_ADYEN_PAYMENT_INFO_ID = 'adyenPaymentInfoId'; @@ -136,7 +135,6 @@ private function uninstallAttributes(UninstallContext $uninstallContext): void { $crudService = $this->container->get('shopware_attribute.crud_service'); $crudService->delete('s_core_paymentmeans_attributes', self::ADYEN_CODE); - $crudService->delete('s_core_paymentmeans_attributes', self::ADYEN_STORED_METHOD_ID); $this->rebuildAttributeModels(); } @@ -157,16 +155,6 @@ private function installAttributes(): void 'label' => 'Adyen payment type', ] ); - $crudService->update( - 's_core_paymentmeans_attributes', - self::ADYEN_STORED_METHOD_ID, - TypeMapping::TYPE_STRING, - [ - 'displayInBackend' => true, - 'readonly' => true, - 'label' => 'Adyen stored payment method id', - ] - ); $this->rebuildAttributeModels(); } diff --git a/Doctrine/Writer/PaymentAttributeWriter.php b/Doctrine/Writer/PaymentAttributeWriter.php index 53fd42dc..ceefd14a 100644 --- a/Doctrine/Writer/PaymentAttributeWriter.php +++ b/Doctrine/Writer/PaymentAttributeWriter.php @@ -23,10 +23,7 @@ public function __construct(DataPersisterInterface $dataPersister, AttributeWrit public function __invoke(int $paymentMeanId, PaymentMethod $adyenPaymentMethod): void { - $attributesColumns = [ - AdyenPayment::ADYEN_CODE => TypeMappingInterface::TYPE_STRING, - AdyenPayment::ADYEN_STORED_METHOD_ID => TypeMappingInterface::TYPE_STRING, - ]; + $attributesColumns = [AdyenPayment::ADYEN_CODE => TypeMappingInterface::TYPE_STRING]; $dataPersister = $this->dataPersister; $this->attributeUpdater->writeReadOnlyAttributes( @@ -37,7 +34,6 @@ public function __invoke(int $paymentMeanId, PaymentMethod $adyenPaymentMethod): '_table' => $table, '_foreignKey' => $paymentMeanId, AdyenPayment::ADYEN_CODE => $adyenPaymentMethod->code(), - AdyenPayment::ADYEN_STORED_METHOD_ID => $adyenPaymentMethod->getStoredPaymentMethodId(), ], 's_core_paymentmeans_attributes', $paymentMeanId diff --git a/Enricher/Payment/PaymentMethodEnricher.php b/Enricher/Payment/PaymentMethodEnricher.php index 57805705..21b67139 100644 --- a/Enricher/Payment/PaymentMethodEnricher.php +++ b/Enricher/Payment/PaymentMethodEnricher.php @@ -4,11 +4,9 @@ namespace AdyenPayment\Enricher\Payment; -use AdyenPayment\AdyenPayment; use AdyenPayment\Components\Adyen\PaymentMethod\ImageLogoProviderInterface; use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMethod; -use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; use Shopware_Components_Snippet_Manager; final class PaymentMethodEnricher implements PaymentMethodEnricherInterface @@ -65,9 +63,6 @@ private function enrichStoredPaymentMethodData(array $shopwareMethod, PaymentMet return []; } - $attribute = $shopwareMethod['attribute'] ?? new Attribute(); - $attribute->set(AdyenPayment::ADYEN_STORED_METHOD_ID, $paymentMethod->getStoredPaymentMethodId()); - return [ 'stored_method_umbrella_id' => sprintf( '%s_%s', @@ -77,7 +72,6 @@ private function enrichStoredPaymentMethodData(array $shopwareMethod, PaymentMet 'stored_method_id' => $paymentMethod->getStoredPaymentMethodId(), 'description' => $paymentMethod->getValue('name'), 'source' => SourceType::adyen()->getType(), - 'attribute' => $attribute, ]; } } diff --git a/Models/Payment/PaymentMean.php b/Models/Payment/PaymentMean.php index 5cc2ed78..1dcfcf78 100644 --- a/Models/Payment/PaymentMean.php +++ b/Models/Payment/PaymentMean.php @@ -64,11 +64,7 @@ public function getAdyenCode(): string public function getAdyenStoredMethodId(): string { - if ($this->getAttribute()->exists(AdyenPayment::ADYEN_STORED_METHOD_ID)) { - return (string) $this->getAttribute()->get(AdyenPayment::ADYEN_STORED_METHOD_ID); - } - - return ''; + return (string) $this->getValue('stored_method_id', ''); } public function adyenType(): ?PaymentType diff --git a/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php index 8f13a0e1..eaac913a 100644 --- a/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php +++ b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php @@ -115,11 +115,11 @@ public function it_can_fetch_a_method_by_payment_mean(): void { $attribute = new Attribute(); $attribute->set(AdyenPayment::ADYEN_CODE, 'my_adyen_code'); - $attribute->set(AdyenPayment::ADYEN_STORED_METHOD_ID, $methodStoredId = 1); $paymentMean = PaymentMean::createFromShopwareArray([ - 'id' => $methodStoredId, + 'id' => $methodStoredId = 'test_stored_method_id', 'source' => 1425514, 'attribute' => $attribute, + 'stored_method_id' => $methodStoredId, ]); $testPayment = PaymentMethod::fromRaw(['type' => 'someType']); $expectedPayment = PaymentMethod::fromRaw(['type' => 'someType2', 'id' => $methodStoredId]); diff --git a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php index f0ef9957..3405c4b4 100644 --- a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php +++ b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php @@ -126,7 +126,6 @@ public function it_does_not_enrich_non_adyen_methods(): void 'source' => SourceType::shopwareDefault()->getType(), 'attribute' => new Attribute([ 'adyen_type' => $adyenIdentifier, - 'adyen_stored_method_id' => null, ]), ]), ); @@ -191,7 +190,6 @@ public function it_does_not_enrich_payment_means_with_attribute_null_values(): v 'source' => SourceType::adyen()->getType(), 'attribute' => new Attribute([ 'adyen_type' => null, - 'adyen_stored_method_id' => null, ]), ]), ); @@ -220,7 +218,6 @@ public function it_removes_adyen_payment_means_without_matching_adyen_payment_me 'source' => SourceType::adyen()->getType(), 'attribute' => new Attribute([ 'adyen_type' => 'non_matching_adyen_identifier', - 'adyen_stored_method_id' => null, ]), ]), ); @@ -249,7 +246,6 @@ public function it_enriches_adyen_payment_methods(): void 'source' => $source = SourceType::adyen()->getType(), 'attribute' => new Attribute([ 'adyen_type' => $adyenIdentifier, - 'adyen_stored_method_id' => null, ]), ]), $umbrellaMean = PaymentMean::createFromShopwareArray([ diff --git a/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php b/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php index 3c9570f5..d46adb1d 100644 --- a/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php +++ b/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php @@ -4,7 +4,6 @@ namespace AdyenPayment\Tests\Unit\Enricher\Payment; -use AdyenPayment\AdyenPayment; use AdyenPayment\Components\Adyen\PaymentMethod\ImageLogoProviderInterface; use AdyenPayment\Enricher\Payment\PaymentMethodEnricher; use AdyenPayment\Enricher\Payment\PaymentMethodEnricherInterface; @@ -13,7 +12,6 @@ use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; -use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; use Shopware_Components_Snippet_Manager; final class PaymentMethodEnricherTest extends TestCase @@ -110,7 +108,6 @@ public function it_will_enrich_a_payment_method_with_stored_method_data(): void 'stored_method_id' => $storedMethodId, 'description' => $storedMethodName, 'source' => SourceType::adyen()->getType(), - 'attribute' => new Attribute([AdyenPayment::ADYEN_STORED_METHOD_ID => $storedMethodId]), ]; self::assertEquals($expected, $result); diff --git a/tests/Unit/Models/Payment/PaymentMeanTest.php b/tests/Unit/Models/Payment/PaymentMeanTest.php index 322282bb..3b5c7729 100644 --- a/tests/Unit/Models/Payment/PaymentMeanTest.php +++ b/tests/Unit/Models/Payment/PaymentMeanTest.php @@ -21,7 +21,6 @@ protected function setUp(): void 'source' => '1425514', 'attribute' => new Attribute([ 'adyen_type' => 'adyen-type', - 'adyen_stored_method_id' => 'stored payment method id', ]), 'enriched' => true, 'adyenType' => 'adyen-type', @@ -58,7 +57,6 @@ public function it_contains_raw_data(): void 'source' => '1425514', 'attribute' => new Attribute([ 'adyen_type' => 'adyen-type', - 'adyen_stored_method_id' => 'stored payment method id', ]), 'enriched' => true, 'adyenType' => 'adyen-type', @@ -102,7 +100,6 @@ public function it_can_retrieve_an_attribute(): void { $this->assertEquals(new Attribute([ 'adyen_type' => 'adyen-type', - 'adyen_stored_method_id' => 'stored payment method id', ]), $this->paymentMean->getAttribute()); } @@ -119,12 +116,6 @@ public function it_can_retrieve_default_attribute_adyen_type(): void $this->assertEquals('', $paymentMean->getAdyenCode()); } - /** @test */ - public function it_can_retrieve_attribute_adyen_stored_method_id(): void - { - $this->assertEquals('stored payment method id', $this->paymentMean->getAdyenStoredMethodId()); - } - /** @test */ public function it_can_retrieve_default_attribute_adyen_stored_method_id(): void { From 5b40d664e2c251a3279a5f4c52aaf399ef589590 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 14 Jan 2022 12:38:18 +0100 Subject: [PATCH 040/136] ASW-377 - CR fixes --- Resources/services/subscribers.xml | 2 +- ...scriber.php => AddStoredMethodIdOnOrderSubscriber.php} | 2 +- .../Checkout/PersistStoredMehtodIdSubscriberTest.php | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) rename Subscriber/{OrderStoredMethodIdSubscriber.php => AddStoredMethodIdOnOrderSubscriber.php} (95%) diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index 43c5a458..3f73695f 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -53,7 +53,7 @@ - + diff --git a/Subscriber/OrderStoredMethodIdSubscriber.php b/Subscriber/AddStoredMethodIdOnOrderSubscriber.php similarity index 95% rename from Subscriber/OrderStoredMethodIdSubscriber.php rename to Subscriber/AddStoredMethodIdOnOrderSubscriber.php index 40946d71..51de9fca 100644 --- a/Subscriber/OrderStoredMethodIdSubscriber.php +++ b/Subscriber/AddStoredMethodIdOnOrderSubscriber.php @@ -11,7 +11,7 @@ use Enlight_Event_EventArgs; use Shopware\Components\Model\ModelManager; -final class OrderStoredMethodIdSubscriber implements SubscriberInterface +final class AddStoredMethodIdOnOrderSubscriber implements SubscriberInterface { private ModelManager $modelManager; private ObjectRepository $paymentInfoRepository; diff --git a/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php b/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php index f5316e02..bc48e0b5 100644 --- a/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php @@ -46,9 +46,9 @@ public function it_does_nothing_on_wrong_request_action_name(): void $eventArgs = $this->buildEventArgs('', $viewData = []); $eventArgs->getRequest()->setParam('isXHR', true); - $this->subscriber->__invoke($eventArgs); - $this->session->set(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($eventArgs); } /** @test */ @@ -57,9 +57,9 @@ public function it_does_nothing_on_shipping_payment_non_xhr_request(): void $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = []); $eventArgs->getRequest()->setParam('isXHR', false); - $this->subscriber->__invoke($eventArgs); - $this->session->set(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($eventArgs); } /** @test */ From 4aaeea8e5af4a64eaa1d57e28a5b12fdf0c0f816 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 14 Jan 2022 12:58:05 +0100 Subject: [PATCH 041/136] ASW-377 - CR fixes --- .../Payment/PaymentMeanCollectionTest.php | 73 +++++++++---------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php index 0aaa6461..28fed4e6 100644 --- a/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php +++ b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php @@ -12,54 +12,54 @@ final class PaymentMeanCollectionTest extends TestCase { + private PaymentMeanCollection $collection; + + protected function setUp(): void + { + $this->collection = new PaymentMeanCollection(); + } + /** @test */ public function it_implements_iterable(): void { - self::assertInstanceOf(\IteratorAggregate::class, new PaymentMeanCollection()); + self::assertInstanceOf(\IteratorAggregate::class, $this->collection); } /** @test */ public function it_can_count(): void { - $result = PaymentMeanCollection::createFromShopwareArray([['source' => SourceType::adyen()->getType()]]); - - self::assertInstanceOf(\Countable::class, $result); - self::assertCount(1, $result); + self::assertInstanceOf(\Countable::class, $this->collection); + self::assertCount(0, $this->collection); } /** @test */ public function it_can_map_with_a_callback(): void { - $expectedMethod = [true]; $filteredSource = SourceType::adyen(); $collection = PaymentMeanCollection::createFromShopwareArray([ ['source' => $filteredSource->getType()], - ['source' => '1'], ]); - $result = $collection->map(static function(PaymentMean $payment) use ($filteredSource) { - return $payment->getSource()->equals($filteredSource); - }); + $result = $collection->map(static fn(PaymentMean $payment) => ['mapped']); - self::assertEquals($expectedMethod, $result); + self::assertEquals([['mapped']], $result); } /** @test */ public function it_can_filter_by_source(): void { $filteredSource = SourceType::adyen(); - $expected = PaymentMeanCollection::createFromShopwareArray([ - ['source' => $filteredSource->getType()], - ]); $collection = PaymentMeanCollection::createFromShopwareArray([ - ['source' => $filteredSource->getType()], - ['source' => '1'], + ['id' => $expected = 123, 'source' => $filteredSource->getType()], + ['id' => 456, 'source' => '1'], ]); $result = $collection->filterBySource($filteredSource); - self::assertEquals($expected, $result); + self::assertInstanceOf(PaymentMeanCollection::class, $result); + self::assertCount(1, $result); + self::assertEquals($expected, iterator_to_array($result)[0]->getId()); } /** @test */ @@ -84,29 +84,23 @@ public function it_can_exclude_adyen(): void public function it_can_exclude_hidden(): void { $filteredSource = SourceType::adyen(); - $expected = PaymentMeanCollection::createFromShopwareArray([ - ['source' => $filteredSource->getType()], - ['source' => '1'], - ]); - $collection = PaymentMeanCollection::createFromShopwareArray([ - ['source' => $filteredSource->getType(), 'hide' => true], - ['source' => $filteredSource->getType()], - ['source' => '1'], - ['source' => '1', 'hide' => true], + ['id' => 123, 'source' => $filteredSource->getType(), 'hide' => true], + ['id' => $expected = 345, 'source' => $filteredSource->getType()], ]); $result = $collection->filterExcludeHidden(); - self::assertEquals($expected, $result); + self::assertInstanceOf(PaymentMeanCollection::class, $result); + self::assertCount(1, $result); + self::assertEquals($expected, iterator_to_array($result)[0]->getId()); } /** @test */ public function it_can_fetch_umbrella_payment_if_available(): void { - $filteredSource = SourceType::adyen(); $collection = PaymentMeanCollection::createFromShopwareArray([ - ['source' => $filteredSource->getType(), 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE], + ['source' => SourceType::adyen()->getType(), 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE], ['source' => '1'], ]); @@ -119,9 +113,8 @@ public function it_can_fetch_umbrella_payment_if_available(): void /** @test */ public function it_will_return_null_on_fetch_umbrella_if_payment_not_available(): void { - $filteredSource = SourceType::adyen(); $collection = PaymentMeanCollection::createFromShopwareArray([ - ['source' => $filteredSource->getType()], + ['source' => SourceType::adyen()->getType()], ['source' => '1'], ]); @@ -133,16 +126,16 @@ public function it_will_return_null_on_fetch_umbrella_if_payment_not_available() /** @test */ public function it_can_fetch_a_payment_by_stored_method_id(): void { - $filteredSource = SourceType::adyen(); $collection = PaymentMeanCollection::createFromShopwareArray([ - ['source' => $filteredSource->getType()], - ['source' => '1', 'stored_method_id' => $testId = 'test123'], + ['id' => 123, 'source' => SourceType::adyen()->getType()], + ['id' => $expected = 456, 'source' => '1', 'stored_method_id' => $paymentMeanId = 'test123'], ]); - $result = $collection->fetchByStoredMethodId($testId); + $result = $collection->fetchByStoredMethodId($paymentMeanId); self::assertInstanceOf(PaymentMean::class, $result); self::assertEquals(1, $result->getSource()->getType()); + self::assertEquals($expected, $result->getId()); } /** @test */ @@ -150,18 +143,18 @@ public function it_can_fetch_a_payment_by_payment_id(): void { $filteredSource = SourceType::adyen(); $collection = PaymentMeanCollection::createFromShopwareArray([ - ['id' => $testId = 123, 'source' => $filteredSource->getType()], - ['' => '456', 'source' => '1'], + ['id' => $paymentMeanId = 123, 'source' => $filteredSource->getType()], + ['id' => '456', 'source' => '1'], ]); - $result = $collection->fetchById($testId); + $result = $collection->fetchById($paymentMeanId); self::assertInstanceOf(PaymentMean::class, $result); - self::assertEquals(123, $result->getId()); + self::assertEquals($paymentMeanId, $result->getId()); } /** @test */ - public function it_will_return_null_on_fetch_by_stored_method_id_if_payment_not_available(): void + public function it_returns_collection_in_shopware_array_format(): void { $filteredSource = SourceType::adyen(); $paymentData = ['id' => '123', 'source' => $filteredSource->getType()]; From 59152796c15c1e69bea24ea0f2d131cfda6bbf09 Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 27 Jan 2022 10:55:29 +0100 Subject: [PATCH 042/136] ASW-377 fix add subshops on install/update --- AdyenPayment.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AdyenPayment.php b/AdyenPayment.php index 654adcbb..89359a29 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -22,6 +22,7 @@ use Shopware\Components\Plugin\Context\UninstallContext; use Shopware\Components\Plugin\Context\UpdateContext; use Shopware\Models\Payment\Payment; +use Shopware\Models\Shop\Shop; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -189,6 +190,9 @@ private function installStoredPaymentUmbrella(InstallContext $context): void /** @var ModelManager $modelsManager */ $modelsManager = $this->container->get(ModelManager::class); + $models = $this->container->get('models'); + $shops = $models->getRepository(Shop::class)->findAll(); + $payment = new Payment(); $payment->setActive(true); $payment->setName(self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE); @@ -197,6 +201,7 @@ private function installStoredPaymentUmbrella(InstallContext $context): void $payment->setPluginId($context->getPlugin()->getId()); $payment->setDescription($description = 'Adyen Stored Payment Method'); $payment->setAdditionalDescription($description); + $payment->setShops($shops); $paymentId = $database->fetchRow( 'SELECT `id` FROM `s_core_paymentmeans` WHERE `name` = :name', From 27175a723866a651873d59b2611ac254f4556d59 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 31 Jan 2022 12:54:07 +0100 Subject: [PATCH 043/136] ASW-461 - My account preselected stored methods --- AdyenPayment.php | 2 + Components/Manager/UserPreferenceManager.php | 37 +++++++++ .../UserPreferenceManagerInterface.php | 14 ++++ Models/UserPreference.php | 81 +++++++++++++++++++ Resources/services/managers.xml | 3 + Resources/services/subscribers.xml | 10 +++ .../frontend/register/payment_fieldset.tpl | 22 ++--- ...istPreselectedStoredMethodIdSubscriber.php | 59 ++++++++++++++ .../PersistStoredMethodIdSubscriber.php | 1 - Subscriber/EnrichUserPreferenceSubscriber.php | 40 +++++++++ 10 files changed, 259 insertions(+), 10 deletions(-) create mode 100644 Components/Manager/UserPreferenceManager.php create mode 100644 Components/Manager/UserPreferenceManagerInterface.php create mode 100644 Models/UserPreference.php create mode 100644 Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php create mode 100755 Subscriber/EnrichUserPreferenceSubscriber.php diff --git a/AdyenPayment.php b/AdyenPayment.php index 89359a29..44476daa 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -12,6 +12,7 @@ use AdyenPayment\Models\PaymentInfo; use AdyenPayment\Models\Refund; use AdyenPayment\Models\TextNotification; +use AdyenPayment\Models\UserPreference; use Doctrine\ORM\Tools\SchemaTool; use Shopware\Bundle\AttributeBundle\Service\TypeMapping; use Shopware\Components\Logger; @@ -169,6 +170,7 @@ private function getModelMetaData(): array $entityManager->getClassMetadata(PaymentInfo::class), $entityManager->getClassMetadata(Refund::class), $entityManager->getClassMetadata(TextNotification::class), + $entityManager->getClassMetadata(UserPreference::class), ]; } diff --git a/Components/Manager/UserPreferenceManager.php b/Components/Manager/UserPreferenceManager.php new file mode 100644 index 00000000..65ad3cf4 --- /dev/null +++ b/Components/Manager/UserPreferenceManager.php @@ -0,0 +1,37 @@ +modelManager = $modelManager; + } + + public function upsertStoredMethodIdByUserId(int $userId, ?string $storedMethodId): void + { + $userPreferenceRepository = $this->modelManager->getRepository(UserPreference::class); + $userPreference = $userPreferenceRepository->findOneBy(['userId' => $userId]); + if (null === $userPreference) { + $userPreference = new UserPreference(); + $userPreference->setUserId($userId); + } + + $this->updateStoredMethodId($userPreference, $storedMethodId); + } + + public function updateStoredMethodId(UserPreference $userPreference, ?string $storedMethodId): void + { + $userPreference = $userPreference->setStoredMethodId($storedMethodId); + $this->modelManager->persist($userPreference); + $this->modelManager->flush($userPreference); + } +} diff --git a/Components/Manager/UserPreferenceManagerInterface.php b/Components/Manager/UserPreferenceManagerInterface.php new file mode 100644 index 00000000..422ccac4 --- /dev/null +++ b/Components/Manager/UserPreferenceManagerInterface.php @@ -0,0 +1,14 @@ +id; + } + + public function setId(int $id): self + { + $this->id = $id; + + return $this; + } + + public function getUserId(): int + { + return $this->userId; + } + + public function setUserId(int $userId): self + { + $this->userId = $userId; + + return $this; + } + + public function getStoredMethodId(): ?string + { + return $this->storedMethodId; + } + + public function setStoredMethodId(?string $storedMethodId): self + { + $this->storedMethodId = $storedMethodId; + + return $this; + } + + public function jsonSerialize() + { + return [ + 'id' => $this->getId(), + 'userId' => $this->getUserId(), + 'storedMethodId' => $this->getStoredMethodId(), + ]; + } +} diff --git a/Resources/services/managers.xml b/Resources/services/managers.xml index b466ed62..dfbd4728 100644 --- a/Resources/services/managers.xml +++ b/Resources/services/managers.xml @@ -21,5 +21,8 @@ + + + diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index 3f73695f..1ca02820 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -111,5 +111,15 @@ + + + + + + + + + + diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl index e3217d28..249b251b 100644 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -2,14 +2,18 @@ {block name="frontend_register_payment_fieldset_input_radio"} {assign var='isStoredPayment' value=('isStoredPayment'|array_key_exists:$payment_mean && true === $payment_mean.isStoredPayment)} - {if not $isStoredPayment} - + {assign var='shouldBeChecked' value=false} + {if $isStoredPayment} + {append var="payment_mean" value=($payment_mean.stored_method_umbrella_id) index='id'} + {if $payment_mean.stored_method_id === $adyenUserPreference.storedMethodId} + {assign var='shouldBeChecked' value=true} + {/if} {/if} -{/block} - -{block name="frontend_register_payment_fieldset_input_label"} - {assign var='isStoredPayment' value=('isStoredPayment'|array_key_exists:$payment_mean && true === $payment_mean.isStoredPayment)} - - {$payment_mean.description} - + {/block} diff --git a/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php b/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php new file mode 100644 index 00000000..467b77eb --- /dev/null +++ b/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php @@ -0,0 +1,59 @@ +session = $session; + $this->userPreferenceManager = $userPreferenceManager; + } + + public static function getSubscribedEvents(): array + { + return ['Enlight_Controller_Action_PostDispatch_Frontend_Account' => '__invoke']; + } + + public function __invoke(\Enlight_Controller_ActionEventArgs $args): void + { + $userId = $this->session->get('sUserId'); + if (!$userId) { + return; + } + + $request = $args->getRequest(); + + $isSavePayment = 'savePayment' === $request->getActionName() && $request->isPost(); + if (!$isSavePayment) { + return; + } + + $storedMethodId = $this->storedMethodIdFromRequest($request); + $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, $storedMethodId); + } + + private function storedMethodIdFromRequest(Enlight_Controller_Request_Request $request): ?string + { + $registerPayment = $request->getParam('register', [])['payment'] ?? null; + if (null === $registerPayment) { + return null; + } + + $splitMethod = explode('_', $registerPayment); + + return 1 < count($splitMethod) ? $splitMethod[1] : null; + } +} diff --git a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php index 204c7d13..6642a4bf 100644 --- a/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php +++ b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php @@ -24,7 +24,6 @@ public static function getSubscribedEvents(): array public function __invoke(\Enlight_Controller_ActionEventArgs $args): void { - $subject = $args->getSubject(); $actionName = $args->getRequest()->getActionName(); $isShippingPaymentUpdate = 'shippingPayment' === $actionName && $args->getRequest()->getParam('isXHR'); diff --git a/Subscriber/EnrichUserPreferenceSubscriber.php b/Subscriber/EnrichUserPreferenceSubscriber.php new file mode 100755 index 00000000..18ae4b33 --- /dev/null +++ b/Subscriber/EnrichUserPreferenceSubscriber.php @@ -0,0 +1,40 @@ +session = $session; + $this->modelsManager = $modelsManager; + } + + public static function getSubscribedEvents(): array + { + return ['Enlight_Controller_Action_PostDispatch_Frontend' => '__invoke']; + } + + public function __invoke(\Enlight_Controller_ActionEventArgs $args): void + { + $userId = $this->session->get('sUserId'); + if (!$userId) { + return; + } + + $userPreference = $this->modelsManager->getRepository(UserPreference::class)->findOneBy(['userId' => $userId]); + $args->getSubject()->View()->assign('adyenUserPreference', $userPreference->jsonSerialize()); + } +} From 65983192c68c2160cef3ea20e02d01dfc093807f Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 08:29:41 +0100 Subject: [PATCH 044/136] ASW-461 - Preselected stored methods in checkout --- .../EnrichUmbrellaPaymentMeanSubscriber.php | 19 +++++++++++++++++-- Subscriber/EnrichUserPreferenceSubscriber.php | 6 +++++- ...nrichUmbrellaPaymentMeanSubscriberTest.php | 3 ++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php index 7578a0c0..bccbe291 100644 --- a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php +++ b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php @@ -37,12 +37,27 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } + $enrichedPaymentMeans = PaymentMeanCollection::createFromShopwareArray(($this->paymentMeansProvider)()); + $userData = $subject->View()->getAssign('sUserData'); + + // if the stored method is not saved in session it means it was not selected in the payment step $storedMethodId = $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); if (null === $storedMethodId) { - return; + $umbrellaPayment = $enrichedPaymentMeans->fetchStoredMethodUmbrellaPaymentMean(); + if (null === $umbrellaPayment) { + return; + } + // but if the umbrella payment is in the user data it means a stored method was preselected by the user + if ($umbrellaPayment->getId() !== (int) $userData['additional']['payment']['id']) { + return; + } + // we use the saved user preference to get the stored method and allow the rest of the flow work normally + $storedMethodId = $args->getSubject()->View()->getAssign('adyenUserPreference')['storedMethodId'] ?? null; } - $enrichedPaymentMeans = PaymentMeanCollection::createFromShopwareArray(($this->paymentMeansProvider)()); + if (null === $storedMethodId) { + return; + } $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodId($storedMethodId); if (null === $paymentMean) { diff --git a/Subscriber/EnrichUserPreferenceSubscriber.php b/Subscriber/EnrichUserPreferenceSubscriber.php index 18ae4b33..330b1beb 100755 --- a/Subscriber/EnrichUserPreferenceSubscriber.php +++ b/Subscriber/EnrichUserPreferenceSubscriber.php @@ -24,7 +24,11 @@ public function __construct( public static function getSubscribedEvents(): array { - return ['Enlight_Controller_Action_PostDispatch_Frontend' => '__invoke']; + return [ + // inject in the view as early as possible to get the info in the other subscribers + 'Enlight_Controller_Action_PostDispatch_Frontend_Account' => ['__invoke', -99999], + 'Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => ['__invoke', -99999], + ]; } public function __invoke(\Enlight_Controller_ActionEventArgs $args): void diff --git a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php index 506e0600..6fae8716 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -72,6 +72,7 @@ public function it_does_nothing_on_missing_session_stored_method_id(): void $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = ['data' => 'view-data']); $eventArgs->getRequest()->setParam('isXHR', false); + $this->paymentMeansProvider->__invoke()->willReturn([]); $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); $this->subscriber->__invoke($eventArgs); @@ -84,8 +85,8 @@ public function it_does_nothing_on_missing_payment_mean_for_stored_method(): voi $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = ['data' => 'view-data']); $eventArgs->getRequest()->setParam('isXHR', false); - $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn($storedMethodId = 'method-id'); $this->paymentMeansProvider->__invoke()->willReturn([]); + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn($storedMethodId = 'method-id'); $this->subscriber->__invoke($eventArgs); $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } From 99dd4c2d12ac1c394b58eead4be860f80c7144b0 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 10:11:47 +0100 Subject: [PATCH 045/136] ASW-461 - Fixed unit tests --- .../EnrichUmbrellaPaymentMeanSubscriber.php | 10 +++- ...nrichUmbrellaPaymentMeanSubscriberTest.php | 56 ++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php index bccbe291..48278541 100644 --- a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php +++ b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php @@ -6,6 +6,7 @@ use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; +use AdyenPayment\Exceptions\UmbrellaPaymentMeanNotFoundException; use AdyenPayment\Shopware\Provider\PaymentMeansProviderInterface; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; @@ -43,12 +44,17 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void // if the stored method is not saved in session it means it was not selected in the payment step $storedMethodId = $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); if (null === $storedMethodId) { + $preselectedPaymentId = $userData['additional']['payment']['id'] ?? null; + if (null === $preselectedPaymentId) { + return; + } + $umbrellaPayment = $enrichedPaymentMeans->fetchStoredMethodUmbrellaPaymentMean(); if (null === $umbrellaPayment) { - return; + throw UmbrellaPaymentMeanNotFoundException::missingUmbrellaPaymentMean(); } // but if the umbrella payment is in the user data it means a stored method was preselected by the user - if ($umbrellaPayment->getId() !== (int) $userData['additional']['payment']['id']) { + if ($umbrellaPayment->getId() !== (int) $preselectedPaymentId) { return; } // we use the saved user preference to get the stored method and allow the rest of the flow work normally diff --git a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php index 6fae8716..9caba057 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -5,6 +5,7 @@ namespace AdyenPayment\Tests\Unit\Subscriber\Checkout; use AdyenPayment\AdyenPayment; +use AdyenPayment\Exceptions\UmbrellaPaymentMeanNotFoundException; use AdyenPayment\Shopware\Provider\PaymentMeansProviderInterface; use AdyenPayment\Subscriber\Checkout\EnrichUmbrellaPaymentMeanSubscriber; use AdyenPayment\Tests\Unit\Subscriber\SubscriberTestCase; @@ -67,13 +68,29 @@ public function it_does_nothing_on_xhr_request(): void } /** @test */ - public function it_does_nothing_on_missing_session_stored_method_id(): void + public function it_does_nothing_on_missing_session_and_none_preselected_stored_method_id(): void { $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = ['data' => 'view-data']); $eventArgs->getRequest()->setParam('isXHR', false); + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); $this->paymentMeansProvider->__invoke()->willReturn([]); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_throws_an_exception_on_missing_missing_umbrella_method_for_preselected_payment(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = [ + 'sUserData' => ['additional' => ['payment' => ['id' => 'preselectedPaymentId']]], + ]); + $eventArgs->getRequest()->setParam('isXHR', false); + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); + $this->paymentMeansProvider->__invoke()->willReturn([]); + self::expectException(UmbrellaPaymentMeanNotFoundException::class); $this->subscriber->__invoke($eventArgs); $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); @@ -91,6 +108,43 @@ public function it_does_nothing_on_missing_payment_mean_for_stored_method(): voi $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } + /** @test */ + public function it_use_the_preselected_stored_method_id_on_preselected_umbrella_payment(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = [ + 'adyenUserPreference' => ['storedMethodId' => $preselectedStoredMethod = 'any-stored-method-id'], + 'sUserData' => ['additional' => ['payment' => ['id' => $preselectedUmbrellaId = 'umbrellaPaymentId']]], + 'sFormData' => [], + ]); + $eventArgs->getRequest()->setParam('isXHR', false); + + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); + $this->paymentMeansProvider->__invoke()->willReturn([ + $umbrellaPaymentMeanRaw = [ + 'id' => $preselectedUmbrellaId, + 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, + 'source' => 123, + 'adyenType' => 'test', + ], + $paymentMeanRaw = [ + 'source' => 1234, + 'adyenType' => 'test', + 'stored_method_id' => $preselectedStoredMethod, + 'stored_method_umbrella_id' => $umbrellaId = 'umbrella-id', + ], + ]); + + $this->subscriber->__invoke($eventArgs); + + $expected = [ + 'adyenUserPreference' => ['storedMethodId' => $preselectedStoredMethod], + 'sUserData' => ['additional' => ['payment' => $paymentMeanRaw]], + 'sFormData' => ['payment' => $umbrellaId], + ]; + + $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + } + /** @test */ public function it_will_enrich_the_payment_mean_for_stored_method(): void { From 9b8a458a5f4659944cb7b31fbe14235961b0e106 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 10:44:08 +0100 Subject: [PATCH 046/136] ASW-461 - New unit test --- Components/Manager/UserPreferenceManager.php | 7 +- .../UserPreferenceManagerInterface.php | 4 - .../Manager/UserPreferenceManagerTest.php | 77 +++++++++++++++++++ 3 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 tests/Unit/Components/Manager/UserPreferenceManagerTest.php diff --git a/Components/Manager/UserPreferenceManager.php b/Components/Manager/UserPreferenceManager.php index 65ad3cf4..b80dce06 100644 --- a/Components/Manager/UserPreferenceManager.php +++ b/Components/Manager/UserPreferenceManager.php @@ -20,17 +20,14 @@ public function upsertStoredMethodIdByUserId(int $userId, ?string $storedMethodI { $userPreferenceRepository = $this->modelManager->getRepository(UserPreference::class); $userPreference = $userPreferenceRepository->findOneBy(['userId' => $userId]); + if (null === $userPreference) { $userPreference = new UserPreference(); $userPreference->setUserId($userId); } - $this->updateStoredMethodId($userPreference, $storedMethodId); - } - - public function updateStoredMethodId(UserPreference $userPreference, ?string $storedMethodId): void - { $userPreference = $userPreference->setStoredMethodId($storedMethodId); + $this->modelManager->persist($userPreference); $this->modelManager->flush($userPreference); } diff --git a/Components/Manager/UserPreferenceManagerInterface.php b/Components/Manager/UserPreferenceManagerInterface.php index 422ccac4..e63f7215 100644 --- a/Components/Manager/UserPreferenceManagerInterface.php +++ b/Components/Manager/UserPreferenceManagerInterface.php @@ -4,11 +4,7 @@ namespace AdyenPayment\Components\Manager; -use AdyenPayment\Models\UserPreference; - interface UserPreferenceManagerInterface { public function upsertStoredMethodIdByUserId(int $userId, ?string $storedMethodId); - - public function updateStoredMethodId(UserPreference $userPreference, ?string $storedMethodId); } diff --git a/tests/Unit/Components/Manager/UserPreferenceManagerTest.php b/tests/Unit/Components/Manager/UserPreferenceManagerTest.php new file mode 100644 index 00000000..7dc7fc31 --- /dev/null +++ b/tests/Unit/Components/Manager/UserPreferenceManagerTest.php @@ -0,0 +1,77 @@ +modelManager = $this->prophesize(EntityManager::class); + + $this->userPreferenceManager = new UserPreferenceManager($this->modelManager->reveal()); + } + + /** @test */ + public function it_is_an_user_preference_manager(): void + { + $this->assertInstanceOf(UserPreferenceManagerInterface::class, $this->userPreferenceManager); + } + + /** @test */ + public function it_can_insert_a_new_record(): void + { + $repositoryMock = $this->prophesize(EntityRepository::class); + $repositoryMock->findOneBy(['userId' => $userId = 1234])->willReturn(null); + + $userPreference = new UserPreference(); + $userPreference->setUserId($userId); + $userPreference->setStoredMethodId($storedMethodId = 'expected-method-id'); + + $this->modelManager->getRepository(UserPreference::class)->willReturn($repositoryMock); + + $this->modelManager->persist($userPreference)->shouldBeCalled(); + $this->modelManager->flush($userPreference)->shouldBeCalled(); + + $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, $storedMethodId); + } + + /** @test */ + public function it_can_update_a_record(): void + { + $existentUserPreference = new UserPreference(); + $existentUserPreference->setUserId($userId = 1234); + $existentUserPreference->setStoredMethodId($oldStoredMethodId = 'expected-method-id'); + + $userPreference = new UserPreference(); + $userPreference->setUserId($userId); + $userPreference->setStoredMethodId($storedMethodId = 'expected-method-id'); + + $repositoryMock = $this->prophesize(EntityRepository::class); + $repositoryMock->findOneBy(['userId' => $userId])->willReturn($existentUserPreference); + + $this->modelManager->getRepository(UserPreference::class)->willReturn($repositoryMock); + $this->modelManager->persist($userPreference)->shouldBeCalled(); + $this->modelManager->flush($userPreference)->shouldBeCalled(); + + $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, $storedMethodId); + } +} From b56b3f863321ad45f46e6c9cb034aa3972e5f59b Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 11:28:08 +0100 Subject: [PATCH 047/136] ASW-461 - Account subscriber unit test --- ...istPreselectedStoredMethodIdSubscriber.php | 4 +- ...reselectedStoredMethodIdSubscriberTest.php | 124 ++++++++++++++++++ tests/Unit/Subscriber/SubscriberTestCase.php | 10 +- 3 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php diff --git a/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php b/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php index 467b77eb..f53ba514 100644 --- a/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php +++ b/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php @@ -30,7 +30,7 @@ public static function getSubscribedEvents(): array public function __invoke(\Enlight_Controller_ActionEventArgs $args): void { $userId = $this->session->get('sUserId'); - if (!$userId) { + if (null === $userId) { return; } @@ -42,7 +42,7 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void } $storedMethodId = $this->storedMethodIdFromRequest($request); - $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, $storedMethodId); + $this->userPreferenceManager->upsertStoredMethodIdByUserId((int) $userId, $storedMethodId); } private function storedMethodIdFromRequest(Enlight_Controller_Request_Request $request): ?string diff --git a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php new file mode 100644 index 00000000..e9ca8b03 --- /dev/null +++ b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php @@ -0,0 +1,124 @@ +args = $this->prophesize(Enlight_Controller_ActionEventArgs::class); + $this->request = $this->prophesize(Enlight_Controller_Request_Request::class); + $this->session = $this->prophesize(Enlight_Components_Session_Namespace::class); + $this->userPreferenceManager = $this->prophesize(UserPreferenceManagerInterface::class); + + $this->subscriber = new PersistPreselectedStoredMethodIdSubscriber( + $this->session->reveal(), + $this->userPreferenceManager->reveal() + ); + } + + /** @test */ + public function it_is_a_subscriber(): void + { + self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); + } + + /** @test */ + public function it_subscribe_to_the_proper_events(): void + { + self::assertEquals( + ['Enlight_Controller_Action_PostDispatch_Frontend_Account' => '__invoke'], + PersistPreselectedStoredMethodIdSubscriber::getSubscribedEvents() + ); + } + + /** @test */ + public function it_does_nothing_on_missing_user_id(): void + { + $this->session->get('sUserId')->willReturn(null); + $this->request->getActionName()->shouldNotBeCalled(); + $this->request->isPost()->shouldNotBeCalled(); + $this->args->getRequest()->shouldNotBeCalled(); + $this->userPreferenceManager->upsertStoredMethodIdByUserId(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_action_name(): void + { + $this->session->get('sUserId')->willReturn(123456); + $this->request->getActionName()->willReturn('wrong-action-name'); + $this->request->isPost()->willReturn(true); + $this->args->getRequest()->willReturn($this->request); + $this->userPreferenceManager->upsertStoredMethodIdByUserId(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_method(): void + { + $this->session->get('sUserId')->willReturn(123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(false); + $this->args->getRequest()->willReturn($this->request); + $this->userPreferenceManager->upsertStoredMethodIdByUserId(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_will_update_the_user_preferences_with_empty_params(): void + { + $this->session->get('sUserId')->willReturn($userId = 123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(true); + $this->request->getParam('register', [])->willReturn([]); + $this->args->getRequest()->willReturn($this->request); + $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, null)->shouldBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_will_update_the_user_preferences_with_param_value(): void + { + $this->session->get('sUserId')->willReturn($userId = 123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(true); + $expected = 'storedMethodId'; + $this->request->getParam('register', [])->willReturn(['payment' => 'proper_'.$expected]); + $this->args->getRequest()->willReturn($this->request); + $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, $expected)->shouldBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } +} diff --git a/tests/Unit/Subscriber/SubscriberTestCase.php b/tests/Unit/Subscriber/SubscriberTestCase.php index e31863b3..4a650e36 100644 --- a/tests/Unit/Subscriber/SubscriberTestCase.php +++ b/tests/Unit/Subscriber/SubscriberTestCase.php @@ -6,6 +6,7 @@ use AdyenPayment\Tests\Unit\Mock\ControllerActionMock; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Webmozart\Assert\Assert; @@ -14,11 +15,16 @@ abstract class SubscriberTestCase extends TestCase protected function buildEventArgs( string $actionName, array $viewData, - int $status = Response::HTTP_OK + int $status = Response::HTTP_OK, + string $requestMethod = Request::METHOD_GET ): \Enlight_Controller_ActionEventArgs { + $request = new \Enlight_Controller_Request_RequestTestCase(); + $request->setActionName($actionName); + $request->setMethod($requestMethod); + return new \Enlight_Controller_ActionEventArgs([ 'subject' => $this->buildSubject($viewData), - 'request' => (new \Enlight_Controller_Request_RequestTestCase())->setActionName($actionName), + 'request' => $request, 'response' => new \Enlight_Controller_Response_ResponseTestCase('', $status), ]); } From c8cd8fb87ce3bbc6f7960f90dfd6ff6a5e342b55 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 11:29:46 +0100 Subject: [PATCH 048/136] ASW-461 - Account subscriber unit test fix --- ...rsistPreselectedStoredMethodIdSubscriberTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php index e9ca8b03..fd89c8a1 100644 --- a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php +++ b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php @@ -108,6 +108,19 @@ public function it_will_update_the_user_preferences_with_empty_params(): void $this->subscriber->__invoke($this->args->reveal()); } + /** @test */ + public function it_will_update_the_user_preferences_with_null_for_wrong_params(): void + { + $this->session->get('sUserId')->willReturn($userId = 123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(true); + $this->request->getParam('register', [])->willReturn(['payment' => 'wrongPayment']); + $this->args->getRequest()->willReturn($this->request); + $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, null)->shouldBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + /** @test */ public function it_will_update_the_user_preferences_with_param_value(): void { From 698ead8e75e99c60acbde30d66f8a9cfa656c0fb Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 11:33:00 +0100 Subject: [PATCH 049/136] ASW-461 - Renamed test --- .../Account/PersistPreselectedStoredMethodIdSubscriberTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php index fd89c8a1..925ccac6 100644 --- a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php +++ b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php @@ -109,7 +109,7 @@ public function it_will_update_the_user_preferences_with_empty_params(): void } /** @test */ - public function it_will_update_the_user_preferences_with_null_for_wrong_params(): void + public function it_will_update_the_user_preferences_with_null_for_none_stored_method_param(): void { $this->session->get('sUserId')->willReturn($userId = 123456); $this->request->getActionName()->willReturn('savePayment'); From 3112b4bce5004ba29dc88d1d30c354854e8d5d7e Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 11:33:47 +0100 Subject: [PATCH 050/136] ASW-461 - Test clarification --- .../Account/PersistPreselectedStoredMethodIdSubscriberTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php index 925ccac6..9024e0d5 100644 --- a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php +++ b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php @@ -114,7 +114,7 @@ public function it_will_update_the_user_preferences_with_null_for_none_stored_me $this->session->get('sUserId')->willReturn($userId = 123456); $this->request->getActionName()->willReturn('savePayment'); $this->request->isPost()->willReturn(true); - $this->request->getParam('register', [])->willReturn(['payment' => 'wrongPayment']); + $this->request->getParam('register', [])->willReturn(['payment' => 'noneStoredPaymentId']); $this->args->getRequest()->willReturn($this->request); $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, null)->shouldBeCalled(); From 6ec9e185ebc1454bbc35e3939b62bae08cc09a43 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 11:35:58 +0100 Subject: [PATCH 051/136] ASW-461 - Unused class --- .../Account/PersistPreselectedStoredMethodIdSubscriberTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php index 9024e0d5..6f914c80 100644 --- a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php +++ b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Prophecy\ObjectProphecy; -use Symfony\Component\HttpFoundation\Request; final class PersistPreselectedStoredMethodIdSubscriberTest extends TestCase { From b4cbd66dd274e190fce94a4035beb47e603f2136 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 1 Feb 2022 11:54:35 +0100 Subject: [PATCH 052/136] ASW-461 - User preference unit test --- .../frontend/register/payment_fieldset.tpl | 2 +- Subscriber/EnrichUserPreferenceSubscriber.php | 6 +- .../EnrichUserPreferenceSubscriberTest.php | 109 ++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl index 249b251b..09205563 100644 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -5,7 +5,7 @@ {assign var='shouldBeChecked' value=false} {if $isStoredPayment} {append var="payment_mean" value=($payment_mean.stored_method_umbrella_id) index='id'} - {if $payment_mean.stored_method_id === $adyenUserPreference.storedMethodId} + {if $adyenUserPreference and $payment_mean.stored_method_id === $adyenUserPreference.storedMethodId} {assign var='shouldBeChecked' value=true} {/if} {/if} diff --git a/Subscriber/EnrichUserPreferenceSubscriber.php b/Subscriber/EnrichUserPreferenceSubscriber.php index 330b1beb..de39c1bc 100755 --- a/Subscriber/EnrichUserPreferenceSubscriber.php +++ b/Subscriber/EnrichUserPreferenceSubscriber.php @@ -34,11 +34,15 @@ public static function getSubscribedEvents(): array public function __invoke(\Enlight_Controller_ActionEventArgs $args): void { $userId = $this->session->get('sUserId'); - if (!$userId) { + if (null === $userId) { return; } $userPreference = $this->modelsManager->getRepository(UserPreference::class)->findOneBy(['userId' => $userId]); + if (null === $userPreference) { + return; + } + $args->getSubject()->View()->assign('adyenUserPreference', $userPreference->jsonSerialize()); } } diff --git a/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php new file mode 100644 index 00000000..3ac3736f --- /dev/null +++ b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php @@ -0,0 +1,109 @@ +session = $this->prophesize(Enlight_Components_Session_Namespace::class); + $this->modelsManager = $this->prophesize(EntityManager::class); + $this->subscriber = new EnrichUserPreferenceSubscriber( + $this->session->reveal(), + $this->modelsManager->reveal() + ); + } + + /** @test */ + public function it_is_a_subscriber(): void + { + self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); + } + + /** @test */ + public function it_subscribe_to_the_proper_events(): void + { + self::assertEquals( + [ + // inject in the view as early as possible to get the info in the other subscribers + 'Enlight_Controller_Action_PostDispatch_Frontend_Account' => ['__invoke', -99999], + 'Enlight_Controller_Action_PostDispatch_Frontend_Checkout' => ['__invoke', -99999], + ], + EnrichUserPreferenceSubscriber::getSubscribedEvents() + ); + } + + /** @test */ + public function it_does_nothing_on_missing_user_id(): void + { + $this->session->get('sUserId')->willReturn(null); + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_missing_user_preference(): void + { + $this->session->get('sUserId')->willReturn($userId = 1234); + + $repositoryMock = $this->prophesize(EntityRepository::class); + $repositoryMock->findOneBy(['userId' => $userId])->willReturn(null); + + $this->modelsManager->getRepository(UserPreference::class)->willReturn($repositoryMock); + + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); + + $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_will_enrich_the_view_with_the_user_preference(): void + { + $this->session->get('sUserId')->willReturn($userId = 1234); + + $userPreference = new UserPreference(); + $userPreference->setId($id = 123123123); + $userPreference->setUserId($userId); + $userPreference->setStoredMethodId($storedMethodId = 'storedMethodId'); + + $repositoryMock = $this->prophesize(EntityRepository::class); + $repositoryMock->findOneBy(['userId' => $userId])->willReturn($userPreference); + + $this->modelsManager->getRepository(UserPreference::class)->willReturn($repositoryMock); + + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); + + $this->subscriber->__invoke($eventArgs); + $expected = [ + 'data' => 'view-data', + 'adyenUserPreference' => [ + 'id' => $id, + 'userId' => $userId, + 'storedMethodId' => $storedMethodId, + ], + ]; + $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + } +} From 6e00a925116170f66a58e84691c4f1227f0a3a37 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 3 Feb 2022 09:38:49 +0100 Subject: [PATCH 053/136] ASW-461 - CR fixes --- Collection/Payment/PaymentMeanCollection.php | 11 + .../StoredPaymentMeanProvider.php | 38 ++++ .../StoredPaymentMeanProviderInterface.php | 13 ++ Components/Manager/UserPreferenceManager.php | 12 +- .../UserPreferenceManagerInterface.php | 4 +- Models/UserPreference.php | 8 +- Resources/services/providers.xml | 4 + Resources/services/subscribers.xml | 6 +- .../frontend/register/payment_fieldset.tpl | 9 +- ...istPreselectedStoredMethodIdSubscriber.php | 59 ----- .../SaveStoredMethodPreferenceSubscriber.php | 64 ++++++ Subscriber/EnrichUserPreferenceSubscriber.php | 13 +- .../Payment/PaymentMeanCollectionTest.php | 15 ++ .../StoredPaymentMeanProviderTest.php | 70 ++++++ .../Manager/UserPreferenceManagerTest.php | 35 +-- ...reselectedStoredMethodIdSubscriberTest.php | 136 ------------ ...veStoredMethodPreferenceSubscriberTest.php | 203 ++++++++++++++++++ ...nrichUmbrellaPaymentMeanSubscriberTest.php | 2 + ...ichUserAdditionalPaymentSubscriberTest.php | 2 + .../PersistStoredMehtodIdSubscriberTest.php | 2 + .../EnrichUserPreferenceSubscriberTest.php | 24 +-- 21 files changed, 457 insertions(+), 273 deletions(-) create mode 100644 Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php create mode 100644 Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php delete mode 100644 Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php create mode 100644 Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php create mode 100644 tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php delete mode 100644 tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php create mode 100644 tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php diff --git a/Collection/Payment/PaymentMeanCollection.php b/Collection/Payment/PaymentMeanCollection.php index 9aab755e..eba89f3b 100644 --- a/Collection/Payment/PaymentMeanCollection.php +++ b/Collection/Payment/PaymentMeanCollection.php @@ -110,6 +110,17 @@ public function fetchByStoredMethodId(string $storedMethodId): ?PaymentMean return null; } + public function fetchByUmbrellaStoredMethodId(string $storedMethodId): ?PaymentMean + { + foreach ($this->paymentMeans as $paymentMean) { + if ($paymentMean->getValue('stored_method_umbrella_id') === $storedMethodId) { + return $paymentMean; + } + } + + return null; + } + public function toShopwareArray(): array { return array_reduce($this->paymentMeans, static function(array $payload, PaymentMean $paymentMean): array { diff --git a/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php new file mode 100644 index 00000000..1bfdd57e --- /dev/null +++ b/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php @@ -0,0 +1,38 @@ +enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + $this->paymentMeansProvider = $paymentMeansProvider; + } + + public function fromRequest(Enlight_Controller_Request_Request $request): ?PaymentMean + { + $registerPayment = $request->getParam('register', [])['payment'] ?? null; + if (null === $registerPayment) { + return null; + } + + $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( + PaymentMeanCollection::createFromShopwareArray(($this->paymentMeansProvider)()) + ); + + return $enrichedPaymentMeans->fetchByUmbrellaStoredMethodId($registerPayment); + } +} diff --git a/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php b/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php new file mode 100644 index 00000000..e7ade33a --- /dev/null +++ b/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php @@ -0,0 +1,13 @@ +modelManager = $modelManager; } - public function upsertStoredMethodIdByUserId(int $userId, ?string $storedMethodId): void + public function save(UserPreference $userPreference): void { - $userPreferenceRepository = $this->modelManager->getRepository(UserPreference::class); - $userPreference = $userPreferenceRepository->findOneBy(['userId' => $userId]); - - if (null === $userPreference) { - $userPreference = new UserPreference(); - $userPreference->setUserId($userId); - } - - $userPreference = $userPreference->setStoredMethodId($storedMethodId); - $this->modelManager->persist($userPreference); $this->modelManager->flush($userPreference); } diff --git a/Components/Manager/UserPreferenceManagerInterface.php b/Components/Manager/UserPreferenceManagerInterface.php index e63f7215..fe8e5262 100644 --- a/Components/Manager/UserPreferenceManagerInterface.php +++ b/Components/Manager/UserPreferenceManagerInterface.php @@ -4,7 +4,9 @@ namespace AdyenPayment\Components\Manager; +use AdyenPayment\Models\UserPreference; + interface UserPreferenceManagerInterface { - public function upsertStoredMethodIdByUserId(int $userId, ?string $storedMethodId); + public function save(UserPreference $userPreference): void; } diff --git a/Models/UserPreference.php b/Models/UserPreference.php index cc37f2b4..ab8c7df0 100644 --- a/Models/UserPreference.php +++ b/Models/UserPreference.php @@ -70,12 +70,8 @@ public function setStoredMethodId(?string $storedMethodId): self return $this; } - public function jsonSerialize() + public function toArray(): array { - return [ - 'id' => $this->getId(), - 'userId' => $this->getUserId(), - 'storedMethodId' => $this->getStoredMethodId(), - ]; + return get_object_vars($this); } } diff --git a/Resources/services/providers.xml b/Resources/services/providers.xml index e02f5105..5c55e0a5 100644 --- a/Resources/services/providers.xml +++ b/Resources/services/providers.xml @@ -8,6 +8,10 @@ + + + + diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index 1ca02820..ef8afb28 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -111,14 +111,16 @@ - + + service('models').getRepository('AdyenPayment\\Models\\UserPreference') + - + service('models').getRepository('AdyenPayment\\Models\\UserPreference') diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl index 09205563..b9667b9c 100644 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -2,18 +2,17 @@ {block name="frontend_register_payment_fieldset_input_radio"} {assign var='isStoredPayment' value=('isStoredPayment'|array_key_exists:$payment_mean && true === $payment_mean.isStoredPayment)} - {assign var='shouldBeChecked' value=false} {if $isStoredPayment} {append var="payment_mean" value=($payment_mean.stored_method_umbrella_id) index='id'} - {if $adyenUserPreference and $payment_mean.stored_method_id === $adyenUserPreference.storedMethodId} - {assign var='shouldBeChecked' value=true} - {/if} {/if} {/block} diff --git a/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php b/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php deleted file mode 100644 index f53ba514..00000000 --- a/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriber.php +++ /dev/null @@ -1,59 +0,0 @@ -session = $session; - $this->userPreferenceManager = $userPreferenceManager; - } - - public static function getSubscribedEvents(): array - { - return ['Enlight_Controller_Action_PostDispatch_Frontend_Account' => '__invoke']; - } - - public function __invoke(\Enlight_Controller_ActionEventArgs $args): void - { - $userId = $this->session->get('sUserId'); - if (null === $userId) { - return; - } - - $request = $args->getRequest(); - - $isSavePayment = 'savePayment' === $request->getActionName() && $request->isPost(); - if (!$isSavePayment) { - return; - } - - $storedMethodId = $this->storedMethodIdFromRequest($request); - $this->userPreferenceManager->upsertStoredMethodIdByUserId((int) $userId, $storedMethodId); - } - - private function storedMethodIdFromRequest(Enlight_Controller_Request_Request $request): ?string - { - $registerPayment = $request->getParam('register', [])['payment'] ?? null; - if (null === $registerPayment) { - return null; - } - - $splitMethod = explode('_', $registerPayment); - - return 1 < count($splitMethod) ? $splitMethod[1] : null; - } -} diff --git a/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php b/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php new file mode 100644 index 00000000..9f4fee65 --- /dev/null +++ b/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php @@ -0,0 +1,64 @@ +session = $session; + $this->userPreferenceManager = $userPreferenceManager; + $this->userPreferenceRepository = $userPreferenceRepository; + $this->storedPaymentMeanProvider = $storedPaymentMeanProvider; + } + + public static function getSubscribedEvents(): array + { + return ['Enlight_Controller_Action_PostDispatch_Frontend_Account' => '__invoke']; + } + + public function __invoke(\Enlight_Controller_ActionEventArgs $args): void + { + $userId = $this->session->get('sUserId'); + if (null === $userId) { + return; + } + + $request = $args->getRequest(); + + $isSavePayment = 'savePayment' === $request->getActionName() && $request->isPost(); + if (!$isSavePayment) { + return; + } + + $storedMethod = $this->storedPaymentMeanProvider->fromRequest($request); + $storedMethodId = null !== $storedMethod ? $storedMethod->getValue('stored_method_id') : null; + + $userPreference = $this->userPreferenceRepository->findOneBy(['userId' => $userId]); + if (null === $userPreference) { + $userPreference = new UserPreference(); + $userPreference->setUserId($userId); + } + + $userPreference = $userPreference->setStoredMethodId($storedMethodId); + $this->userPreferenceManager->save($userPreference); + } +} diff --git a/Subscriber/EnrichUserPreferenceSubscriber.php b/Subscriber/EnrichUserPreferenceSubscriber.php index de39c1bc..fd85e10e 100755 --- a/Subscriber/EnrichUserPreferenceSubscriber.php +++ b/Subscriber/EnrichUserPreferenceSubscriber.php @@ -4,22 +4,21 @@ namespace AdyenPayment\Subscriber; -use AdyenPayment\Models\UserPreference; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityRepository; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; final class EnrichUserPreferenceSubscriber implements SubscriberInterface { private Enlight_Components_Session_Namespace $session; - private EntityManager $modelsManager; + private EntityRepository $userPreferenceRepository; public function __construct( Enlight_Components_Session_Namespace $session, - EntityManager $modelsManager + EntityRepository $userPreferenceRepository ) { $this->session = $session; - $this->modelsManager = $modelsManager; + $this->userPreferenceRepository = $userPreferenceRepository; } public static function getSubscribedEvents(): array @@ -38,11 +37,11 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } - $userPreference = $this->modelsManager->getRepository(UserPreference::class)->findOneBy(['userId' => $userId]); + $userPreference = $this->userPreferenceRepository->findOneBy(['userId' => $userId]); if (null === $userPreference) { return; } - $args->getSubject()->View()->assign('adyenUserPreference', $userPreference->jsonSerialize()); + $args->getSubject()->View()->assign('adyenUserPreference', $userPreference->toArray()); } } diff --git a/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php index 28fed4e6..99ea9bb0 100644 --- a/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php +++ b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php @@ -138,6 +138,21 @@ public function it_can_fetch_a_payment_by_stored_method_id(): void self::assertEquals($expected, $result->getId()); } + /** @test */ + public function it_can_fetch_a_payment_by_stored_method_umbrella_id(): void + { + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['id' => 123, 'source' => SourceType::adyen()->getType()], + ['id' => $expected = 456, 'source' => '1', 'stored_method_umbrella_id' => $paymentMeanId = 'test123'], + ]); + + $result = $collection->fetchByUmbrellaStoredMethodId($paymentMeanId); + + self::assertInstanceOf(PaymentMean::class, $result); + self::assertEquals(1, $result->getSource()->getType()); + self::assertEquals($expected, $result->getId()); + } + /** @test */ public function it_can_fetch_a_payment_by_payment_id(): void { diff --git a/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php new file mode 100644 index 00000000..a58a3907 --- /dev/null +++ b/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php @@ -0,0 +1,70 @@ +enrichedPaymentMeanProvider = $this->prophesize(EnrichedPaymentMeanProviderInterface::class); + $this->paymentMeansProvider = $this->prophesize(PaymentMeansProviderInterface::class); + + $this->storedPaymentMeanProvider = new StoredPaymentMeanProvider( + $this->enrichedPaymentMeanProvider->reveal(), + $this->paymentMeansProvider->reveal(), + ); + } + + /** @test */ + public function it_is_an_stored_payment_mean_provider(): void + { + $this->assertInstanceOf(StoredPaymentMeanProviderInterface::class, $this->storedPaymentMeanProvider); + } + + /** @test */ + public function it_will_return_null_on_missing_params(): void + { + $request = $this->prophesize(Enlight_Controller_Request_Request::class); + $request->getParam('register', [])->willReturn([]); + + $result = $this->storedPaymentMeanProvider->fromRequest($request->reveal()); + + self::assertNull($result); + } + + /** @test */ + public function it_will_try_to_provide_a_payment_by_umbrella_stored_method_id(): void + { + $request = $this->prophesize(Enlight_Controller_Request_Request::class); + $request->getParam('register', [])->willReturn(['payment' => $id = 'stored_method_umbrella_id']); + + $emptyCollection = PaymentMeanCollection::createFromShopwareArray([]); + $this->enrichedPaymentMeanProvider->__invoke($emptyCollection)->willReturn($emptyCollection); + $this->paymentMeansProvider->__invoke()->willReturn([]); + + $result = $this->storedPaymentMeanProvider->fromRequest($request->reveal()); + + self::assertNull($result); + } +} diff --git a/tests/Unit/Components/Manager/UserPreferenceManagerTest.php b/tests/Unit/Components/Manager/UserPreferenceManagerTest.php index 7dc7fc31..4d401d90 100644 --- a/tests/Unit/Components/Manager/UserPreferenceManagerTest.php +++ b/tests/Unit/Components/Manager/UserPreferenceManagerTest.php @@ -8,7 +8,6 @@ use AdyenPayment\Components\Manager\UserPreferenceManagerInterface; use AdyenPayment\Models\UserPreference; use Doctrine\ORM\EntityManager; -use Doctrine\ORM\EntityRepository; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; @@ -37,41 +36,15 @@ public function it_is_an_user_preference_manager(): void } /** @test */ - public function it_can_insert_a_new_record(): void + public function it_can_save_a_record(): void { - $repositoryMock = $this->prophesize(EntityRepository::class); - $repositoryMock->findOneBy(['userId' => $userId = 1234])->willReturn(null); - $userPreference = new UserPreference(); - $userPreference->setUserId($userId); - $userPreference->setStoredMethodId($storedMethodId = 'expected-method-id'); - - $this->modelManager->getRepository(UserPreference::class)->willReturn($repositoryMock); - - $this->modelManager->persist($userPreference)->shouldBeCalled(); - $this->modelManager->flush($userPreference)->shouldBeCalled(); - - $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, $storedMethodId); - } - - /** @test */ - public function it_can_update_a_record(): void - { - $existentUserPreference = new UserPreference(); - $existentUserPreference->setUserId($userId = 1234); - $existentUserPreference->setStoredMethodId($oldStoredMethodId = 'expected-method-id'); - - $userPreference = new UserPreference(); - $userPreference->setUserId($userId); - $userPreference->setStoredMethodId($storedMethodId = 'expected-method-id'); - - $repositoryMock = $this->prophesize(EntityRepository::class); - $repositoryMock->findOneBy(['userId' => $userId])->willReturn($existentUserPreference); + $userPreference->setUserId(1234); + $userPreference->setStoredMethodId('expected-method-id'); - $this->modelManager->getRepository(UserPreference::class)->willReturn($repositoryMock); $this->modelManager->persist($userPreference)->shouldBeCalled(); $this->modelManager->flush($userPreference)->shouldBeCalled(); - $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, $storedMethodId); + $this->userPreferenceManager->save($userPreference); } } diff --git a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php b/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php deleted file mode 100644 index 6f914c80..00000000 --- a/tests/Unit/Subscriber/Account/PersistPreselectedStoredMethodIdSubscriberTest.php +++ /dev/null @@ -1,136 +0,0 @@ -args = $this->prophesize(Enlight_Controller_ActionEventArgs::class); - $this->request = $this->prophesize(Enlight_Controller_Request_Request::class); - $this->session = $this->prophesize(Enlight_Components_Session_Namespace::class); - $this->userPreferenceManager = $this->prophesize(UserPreferenceManagerInterface::class); - - $this->subscriber = new PersistPreselectedStoredMethodIdSubscriber( - $this->session->reveal(), - $this->userPreferenceManager->reveal() - ); - } - - /** @test */ - public function it_is_a_subscriber(): void - { - self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); - } - - /** @test */ - public function it_subscribe_to_the_proper_events(): void - { - self::assertEquals( - ['Enlight_Controller_Action_PostDispatch_Frontend_Account' => '__invoke'], - PersistPreselectedStoredMethodIdSubscriber::getSubscribedEvents() - ); - } - - /** @test */ - public function it_does_nothing_on_missing_user_id(): void - { - $this->session->get('sUserId')->willReturn(null); - $this->request->getActionName()->shouldNotBeCalled(); - $this->request->isPost()->shouldNotBeCalled(); - $this->args->getRequest()->shouldNotBeCalled(); - $this->userPreferenceManager->upsertStoredMethodIdByUserId(Argument::cetera())->shouldNotBeCalled(); - - $this->subscriber->__invoke($this->args->reveal()); - } - - /** @test */ - public function it_does_nothing_on_wrong_request_action_name(): void - { - $this->session->get('sUserId')->willReturn(123456); - $this->request->getActionName()->willReturn('wrong-action-name'); - $this->request->isPost()->willReturn(true); - $this->args->getRequest()->willReturn($this->request); - $this->userPreferenceManager->upsertStoredMethodIdByUserId(Argument::cetera())->shouldNotBeCalled(); - - $this->subscriber->__invoke($this->args->reveal()); - } - - /** @test */ - public function it_does_nothing_on_wrong_request_method(): void - { - $this->session->get('sUserId')->willReturn(123456); - $this->request->getActionName()->willReturn('savePayment'); - $this->request->isPost()->willReturn(false); - $this->args->getRequest()->willReturn($this->request); - $this->userPreferenceManager->upsertStoredMethodIdByUserId(Argument::cetera())->shouldNotBeCalled(); - - $this->subscriber->__invoke($this->args->reveal()); - } - - /** @test */ - public function it_will_update_the_user_preferences_with_empty_params(): void - { - $this->session->get('sUserId')->willReturn($userId = 123456); - $this->request->getActionName()->willReturn('savePayment'); - $this->request->isPost()->willReturn(true); - $this->request->getParam('register', [])->willReturn([]); - $this->args->getRequest()->willReturn($this->request); - $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, null)->shouldBeCalled(); - - $this->subscriber->__invoke($this->args->reveal()); - } - - /** @test */ - public function it_will_update_the_user_preferences_with_null_for_none_stored_method_param(): void - { - $this->session->get('sUserId')->willReturn($userId = 123456); - $this->request->getActionName()->willReturn('savePayment'); - $this->request->isPost()->willReturn(true); - $this->request->getParam('register', [])->willReturn(['payment' => 'noneStoredPaymentId']); - $this->args->getRequest()->willReturn($this->request); - $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, null)->shouldBeCalled(); - - $this->subscriber->__invoke($this->args->reveal()); - } - - /** @test */ - public function it_will_update_the_user_preferences_with_param_value(): void - { - $this->session->get('sUserId')->willReturn($userId = 123456); - $this->request->getActionName()->willReturn('savePayment'); - $this->request->isPost()->willReturn(true); - $expected = 'storedMethodId'; - $this->request->getParam('register', [])->willReturn(['payment' => 'proper_'.$expected]); - $this->args->getRequest()->willReturn($this->request); - $this->userPreferenceManager->upsertStoredMethodIdByUserId($userId, $expected)->shouldBeCalled(); - - $this->subscriber->__invoke($this->args->reveal()); - } -} diff --git a/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php b/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php new file mode 100644 index 00000000..3176137b --- /dev/null +++ b/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php @@ -0,0 +1,203 @@ +args = $this->prophesize(Enlight_Controller_ActionEventArgs::class); + $this->request = $this->prophesize(Enlight_Controller_Request_Request::class); + $this->session = $this->prophesize(Enlight_Components_Session_Namespace::class); + $this->userPreferenceManager = $this->prophesize(UserPreferenceManagerInterface::class); + $this->userPreferenceRepository = $this->prophesize(EntityRepository::class); + $this->storedPaymentMeanProvider = $this->prophesize(StoredPaymentMeanProviderInterface::class); + + $this->subscriber = new SaveStoredMethodPreferenceSubscriber( + $this->session->reveal(), + $this->userPreferenceManager->reveal(), + $this->userPreferenceRepository->reveal(), + $this->storedPaymentMeanProvider->reveal() + ); + } + + /** @test */ + public function it_is_a_subscriber(): void + { + self::assertInstanceOf(SubscriberInterface::class, $this->subscriber); + } + + /** @test */ + public function it_subscribe_to_the_proper_events(): void + { + self::assertEquals( + ['Enlight_Controller_Action_PostDispatch_Frontend_Account' => '__invoke'], + SaveStoredMethodPreferenceSubscriber::getSubscribedEvents() + ); + } + + /** @test */ + public function it_does_nothing_on_missing_user_id(): void + { + $this->session->get('sUserId')->willReturn(null); + $this->request->getActionName()->shouldNotBeCalled(); + $this->request->isPost()->shouldNotBeCalled(); + $this->args->getRequest()->shouldNotBeCalled(); + $this->storedPaymentMeanProvider->fromRequest(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_action_name(): void + { + $this->session->get('sUserId')->willReturn(123456); + $this->request->getActionName()->willReturn('wrong-action-name'); + $this->request->isPost()->willReturn(true); + $this->args->getRequest()->willReturn($this->request); + $this->storedPaymentMeanProvider->fromRequest(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_does_nothing_on_wrong_request_method(): void + { + $this->session->get('sUserId')->willReturn(123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(false); + $this->args->getRequest()->willReturn($this->request); + $this->storedPaymentMeanProvider->fromRequest(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_will_save_the_user_preferences_with_empty_params(): void + { + $this->session->get('sUserId')->willReturn($userId = 123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(true); + $this->request->getParam('register', [])->willReturn([]); + $this->args->getRequest()->willReturn($this->request->reveal()); + $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn(null); + + $userPreference = new UserPreference(); + $userPreference->setUserId($userId); + $userPreference->setStoredMethodId(null); + + $this->userPreferenceManager->save($userPreference)->shouldBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_will_save_the_user_preferences_with_null_for_none_stored_method_param(): void + { + $this->session->get('sUserId')->willReturn($userId = 123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(true); + $this->request->getParam('register', [])->willReturn(['payment' => 'noneStoredPaymentId']); + $this->args->getRequest()->willReturn($this->request->reveal()); + $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn(null); + + $userPreference = new UserPreference(); + $userPreference->setUserId($userId); + $userPreference->setStoredMethodId(null); + + $this->userPreferenceManager->save($userPreference)->shouldBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_will_save_the_user_preferences_with_param_value(): void + { + $this->session->get('sUserId')->willReturn($userId = 123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(true); + $this->request->getParam('register', [])->willReturn([ + 'payment' => 'proper_'.($storedMethodId = 'storedMethodId'), + ]); + $this->args->getRequest()->willReturn($this->request->reveal()); + $storedPaymentMean = PaymentMean::createFromShopwareArray([ + 'source' => 'any', + 'stored_method_id' => $storedMethodId, + ]); + $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedPaymentMean); + + $userPreference = new UserPreference(); + $userPreference->setUserId($userId); + $userPreference->setStoredMethodId($storedMethodId); + + $this->userPreferenceManager->save($userPreference)->shouldBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } + + /** @test */ + public function it_will_update_the_user_preferences_with_param_value(): void + { + $this->session->get('sUserId')->willReturn($userId = 123456); + $this->request->getActionName()->willReturn('savePayment'); + $this->request->isPost()->willReturn(true); + $this->request->getParam('register', [])->willReturn([ + 'payment' => 'proper_'.($storedMethodId = 'storedMethodId'), + ]); + $this->args->getRequest()->willReturn($this->request->reveal()); + $storedPaymentMean = PaymentMean::createFromShopwareArray([ + 'source' => 'any', + 'stored_method_id' => $storedMethodId, + ]); + $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedPaymentMean); + + $userPreference = new UserPreference(); + $userPreference->setId(123); + $userPreference->setUserId($userId); + $userPreference->setStoredMethodId($storedMethodId); + + $this->userPreferenceRepository->findOneBy(['userId' => $userId])->willReturn($userPreference); + + $this->userPreferenceManager->save($userPreference)->shouldBeCalled(); + + $this->subscriber->__invoke($this->args->reveal()); + } +} diff --git a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php index 9caba057..6b8b812c 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -11,10 +11,12 @@ use AdyenPayment\Tests\Unit\Subscriber\SubscriberTestCase; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; +use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; final class EnrichUmbrellaPaymentMeanSubscriberTest extends SubscriberTestCase { + use ProphecyTrait; private EnrichUmbrellaPaymentMeanSubscriber $subscriber; /** @var Enlight_Components_Session_Namespace|ObjectProphecy */ diff --git a/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php index aec923be..c920ecde 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php @@ -12,10 +12,12 @@ use AdyenPayment\Tests\Unit\Subscriber\SubscriberTestCase; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; +use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; final class EnrichUserAdditionalPaymentSubscriberTest extends SubscriberTestCase { + use ProphecyTrait; private EnrichUserAdditionalPaymentSubscriber $subscriber; /** @var EnrichedPaymentMeanProviderInterface|ObjectProphecy */ diff --git a/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php b/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php index bc48e0b5..c55b1386 100644 --- a/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php @@ -10,10 +10,12 @@ use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; final class PersistStoredMehtodIdSubscriberTest extends SubscriberTestCase { + use ProphecyTrait; private PersistStoredMethodIdSubscriber $subscriber; /** @var Enlight_Components_Session_Namespace|ObjectProphecy */ diff --git a/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php index 3ac3736f..2e670ee5 100644 --- a/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php +++ b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php @@ -7,7 +7,6 @@ use AdyenPayment\Models\UserPreference; use AdyenPayment\Subscriber\EnrichUserPreferenceSubscriber; use AdyenPayment\Tests\Unit\Subscriber\SubscriberTestCase; -use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityRepository; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; @@ -20,16 +19,16 @@ final class EnrichUserPreferenceSubscriberTest extends SubscriberTestCase /** @var Enlight_Components_Session_Namespace|ObjectProphecy */ private $session; - /** @var EntityManager|ObjectProphecy */ - private $modelsManager; + /** @var EntityRepository|ObjectProphecy */ + private $userPreferenceRepository; protected function setUp(): void { $this->session = $this->prophesize(Enlight_Components_Session_Namespace::class); - $this->modelsManager = $this->prophesize(EntityManager::class); + $this->userPreferenceRepository = $this->prophesize(EntityRepository::class); $this->subscriber = new EnrichUserPreferenceSubscriber( $this->session->reveal(), - $this->modelsManager->reveal() + $this->userPreferenceRepository->reveal() ); } @@ -59,6 +58,7 @@ public function it_does_nothing_on_missing_user_id(): void $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } @@ -66,15 +66,12 @@ public function it_does_nothing_on_missing_user_id(): void public function it_does_nothing_on_missing_user_preference(): void { $this->session->get('sUserId')->willReturn($userId = 1234); - - $repositoryMock = $this->prophesize(EntityRepository::class); - $repositoryMock->findOneBy(['userId' => $userId])->willReturn(null); - - $this->modelsManager->getRepository(UserPreference::class)->willReturn($repositoryMock); + $this->userPreferenceRepository->findOneBy(['userId' => $userId])->willReturn(null); $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); $this->subscriber->__invoke($eventArgs); + $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } @@ -87,15 +84,12 @@ public function it_will_enrich_the_view_with_the_user_preference(): void $userPreference->setId($id = 123123123); $userPreference->setUserId($userId); $userPreference->setStoredMethodId($storedMethodId = 'storedMethodId'); - - $repositoryMock = $this->prophesize(EntityRepository::class); - $repositoryMock->findOneBy(['userId' => $userId])->willReturn($userPreference); - - $this->modelsManager->getRepository(UserPreference::class)->willReturn($repositoryMock); + $this->userPreferenceRepository->findOneBy(['userId' => $userId])->willReturn($userPreference); $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); $this->subscriber->__invoke($eventArgs); + $expected = [ 'data' => 'view-data', 'adyenUserPreference' => [ From 1bf32efa4cfc2676dd402ef72e49cb043b7d1092 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 3 Feb 2022 11:17:55 +0100 Subject: [PATCH 054/136] ASW-461 - CR fixes --- Models/UserPreference.php | 8 ++++++-- Subscriber/EnrichUserPreferenceSubscriber.php | 4 +++- .../EnrichUmbrellaPaymentMeanSubscriberTest.php | 14 +++++++------- .../EnrichUserAdditionalPaymentSubscriberTest.php | 12 ++++++------ .../EnrichUserPreferenceSubscriberTest.php | 6 +++--- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/Models/UserPreference.php b/Models/UserPreference.php index ab8c7df0..eb65ac23 100644 --- a/Models/UserPreference.php +++ b/Models/UserPreference.php @@ -70,8 +70,12 @@ public function setStoredMethodId(?string $storedMethodId): self return $this; } - public function toArray(): array + public function mapToView(): array { - return get_object_vars($this); + return [ + 'id' => $this->getId(), + 'userId' => $this->getUserId(), + 'storedMethodId' => $this->getStoredMethodId(), + ]; } } diff --git a/Subscriber/EnrichUserPreferenceSubscriber.php b/Subscriber/EnrichUserPreferenceSubscriber.php index fd85e10e..0840cba3 100755 --- a/Subscriber/EnrichUserPreferenceSubscriber.php +++ b/Subscriber/EnrichUserPreferenceSubscriber.php @@ -4,6 +4,7 @@ namespace AdyenPayment\Subscriber; +use AdyenPayment\Models\UserPreference; use Doctrine\ORM\EntityRepository; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; @@ -37,11 +38,12 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } + /** @var UserPreference $userPreference */ $userPreference = $this->userPreferenceRepository->findOneBy(['userId' => $userId]); if (null === $userPreference) { return; } - $args->getSubject()->View()->assign('adyenUserPreference', $userPreference->toArray()); + $args->getSubject()->View()->assign('adyenUserPreference', $userPreference->mapToView()); } } diff --git a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php index 6b8b812c..ccb9dcd8 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -56,7 +56,7 @@ public function it_does_nothing_on_wrong_request_action_name(): void $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -66,7 +66,7 @@ public function it_does_nothing_on_xhr_request(): void $eventArgs->getRequest()->setParam('isXHR', true); $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -79,7 +79,7 @@ public function it_does_nothing_on_missing_session_and_none_preselected_stored_m $this->paymentMeansProvider->__invoke()->willReturn([]); $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -95,7 +95,7 @@ public function it_throws_an_exception_on_missing_missing_umbrella_method_for_pr self::expectException(UmbrellaPaymentMeanNotFoundException::class); $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -107,7 +107,7 @@ public function it_does_nothing_on_missing_payment_mean_for_stored_method(): voi $this->paymentMeansProvider->__invoke()->willReturn([]); $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn($storedMethodId = 'method-id'); $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -144,7 +144,7 @@ public function it_use_the_preselected_stored_method_id_on_preselected_umbrella_ 'sFormData' => ['payment' => $umbrellaId], ]; - $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -171,6 +171,6 @@ public function it_will_enrich_the_payment_mean_for_stored_method(): void 'sFormData' => ['payment' => $umbrellaId], ]; - $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); } } diff --git a/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php index c920ecde..66ce633a 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php @@ -62,7 +62,7 @@ public function it_does_nothing_on_wrong_request_action_name(): void $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -73,7 +73,7 @@ public function it_does_nothing_on_missing_stored_method_id_and_payment_mean_id( $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -92,7 +92,7 @@ public function it_does_nothing_on_missing_payment_mean_for_stored_method_id(): $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -113,7 +113,7 @@ public function it_does_nothing_on_missing_payment_mean_for_payment_id(): void $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -137,7 +137,7 @@ public function it_will_update_the_view_with_payment_mean_for_stored_method_id() 'sUserData' => ['additional' => ['payment' => $paymentMeanRaw]], ]; - $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -163,6 +163,6 @@ public function it_will_update_the_view_with_payment_mean_for_payment_id(): void 'sUserData' => ['additional' => ['payment' => $paymentMeanRaw]], ]; - $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); } } diff --git a/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php index 2e670ee5..92b20638 100644 --- a/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php +++ b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php @@ -59,7 +59,7 @@ public function it_does_nothing_on_missing_user_id(): void $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -72,7 +72,7 @@ public function it_does_nothing_on_missing_user_preference(): void $this->subscriber->__invoke($eventArgs); - $this->assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); } /** @test */ @@ -98,6 +98,6 @@ public function it_will_enrich_the_view_with_the_user_preference(): void 'storedMethodId' => $storedMethodId, ], ]; - $this->assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + self::assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); } } From 7b415c06ec3ef7486e5ef0ac3ebc53acc18362e9 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 3 Feb 2022 11:32:25 +0100 Subject: [PATCH 055/136] ASW-461 - CR fixes --- Models/PaymentInfo.php | 2 +- Models/UserPreference.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Models/PaymentInfo.php b/Models/PaymentInfo.php index 1006f4d7..5b6903ff 100644 --- a/Models/PaymentInfo.php +++ b/Models/PaymentInfo.php @@ -288,7 +288,7 @@ public function setPaymentData(string $paymentData): self public function getStoredMethodId(): string { - return $this->storedMethodId; + return (string) $this->storedMethodId; } public function setStoredMethodId(string $storedMethodId): self diff --git a/Models/UserPreference.php b/Models/UserPreference.php index eb65ac23..92ca3859 100644 --- a/Models/UserPreference.php +++ b/Models/UserPreference.php @@ -58,9 +58,9 @@ public function setUserId(int $userId): self return $this; } - public function getStoredMethodId(): ?string + public function getStoredMethodId(): string { - return $this->storedMethodId; + return (string) $this->storedMethodId; } public function setStoredMethodId(?string $storedMethodId): self From 99f51ac0ac787fe4416ff6a27fd8ff0d81bd1b0a Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 4 Feb 2022 07:37:59 +0100 Subject: [PATCH 056/136] ASW-461 - CR fix --- .../StoredPaymentMeanProvider.php | 23 +++-------------- .../StoredPaymentMeanProviderInterface.php | 3 +-- Resources/services/providers.xml | 5 +--- .../SaveStoredMethodPreferenceSubscriber.php | 3 +-- .../StoredPaymentMeanProviderTest.php | 25 +++++++++++-------- ...veStoredMethodPreferenceSubscriberTest.php | 13 ++-------- .../EnrichUserPreferenceSubscriberTest.php | 2 ++ 7 files changed, 25 insertions(+), 49 deletions(-) diff --git a/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php index 1bfdd57e..dfe6f4b9 100644 --- a/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php @@ -4,35 +4,20 @@ namespace AdyenPayment\Components\Adyen\PaymentMethod; -use AdyenPayment\Collection\Payment\PaymentMeanCollection; -use AdyenPayment\Models\Payment\PaymentMean; -use AdyenPayment\Shopware\Provider\PaymentMeansProviderInterface; use Enlight_Controller_Request_Request; final class StoredPaymentMeanProvider implements StoredPaymentMeanProviderInterface { - private EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider; - private PaymentMeansProviderInterface $paymentMeansProvider; - - public function __construct( - EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider, - PaymentMeansProviderInterface $paymentMeansProvider - ) { - $this->enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; - $this->paymentMeansProvider = $paymentMeansProvider; - } - - public function fromRequest(Enlight_Controller_Request_Request $request): ?PaymentMean + public function fromRequest(Enlight_Controller_Request_Request $request): ?string { $registerPayment = $request->getParam('register', [])['payment'] ?? null; if (null === $registerPayment) { return null; } - $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( - PaymentMeanCollection::createFromShopwareArray(($this->paymentMeansProvider)()) - ); + // at this point the payment param will be the combined id: [SW umbrella ID] + _ + [Adyen stored method ID] + $splitMethod = explode('_', $registerPayment); - return $enrichedPaymentMeans->fetchByUmbrellaStoredMethodId($registerPayment); + return 1 < count($splitMethod) ? $splitMethod[1] : null; } } diff --git a/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php b/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php index e7ade33a..72ddab19 100644 --- a/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php +++ b/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php @@ -4,10 +4,9 @@ namespace AdyenPayment\Components\Adyen\PaymentMethod; -use AdyenPayment\Models\Payment\PaymentMean; use Enlight_Controller_Request_Request; interface StoredPaymentMeanProviderInterface { - public function fromRequest(Enlight_Controller_Request_Request $request): ?PaymentMean; + public function fromRequest(Enlight_Controller_Request_Request $request): ?string; } diff --git a/Resources/services/providers.xml b/Resources/services/providers.xml index 5c55e0a5..e238f9e3 100644 --- a/Resources/services/providers.xml +++ b/Resources/services/providers.xml @@ -8,10 +8,7 @@ - - - - + diff --git a/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php b/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php index 9f4fee65..b30d6d3e 100644 --- a/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php +++ b/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php @@ -49,8 +49,7 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } - $storedMethod = $this->storedPaymentMeanProvider->fromRequest($request); - $storedMethodId = null !== $storedMethod ? $storedMethod->getValue('stored_method_id') : null; + $storedMethodId = $this->storedPaymentMeanProvider->fromRequest($request); $userPreference = $this->userPreferenceRepository->findOneBy(['userId' => $userId]); if (null === $userPreference) { diff --git a/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php index a58a3907..1ecf539c 100644 --- a/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php +++ b/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php @@ -4,7 +4,6 @@ namespace AdyenPayment\Tests\Unit\Components\Adyen\PaymentMethod; -use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProviderInterface; use AdyenPayment\Components\Adyen\PaymentMethod\StoredPaymentMeanProvider; use AdyenPayment\Components\Adyen\PaymentMethod\StoredPaymentMeanProviderInterface; @@ -30,10 +29,7 @@ protected function setUp(): void $this->enrichedPaymentMeanProvider = $this->prophesize(EnrichedPaymentMeanProviderInterface::class); $this->paymentMeansProvider = $this->prophesize(PaymentMeansProviderInterface::class); - $this->storedPaymentMeanProvider = new StoredPaymentMeanProvider( - $this->enrichedPaymentMeanProvider->reveal(), - $this->paymentMeansProvider->reveal(), - ); + $this->storedPaymentMeanProvider = new StoredPaymentMeanProvider(); } /** @test */ @@ -54,17 +50,24 @@ public function it_will_return_null_on_missing_params(): void } /** @test */ - public function it_will_try_to_provide_a_payment_by_umbrella_stored_method_id(): void + public function it_will_return_null_on_none_combined_id_param(): void { $request = $this->prophesize(Enlight_Controller_Request_Request::class); - $request->getParam('register', [])->willReturn(['payment' => $id = 'stored_method_umbrella_id']); - - $emptyCollection = PaymentMeanCollection::createFromShopwareArray([]); - $this->enrichedPaymentMeanProvider->__invoke($emptyCollection)->willReturn($emptyCollection); - $this->paymentMeansProvider->__invoke()->willReturn([]); + $request->getParam('register', [])->willReturn(['payment' => $id = 'anyPaymentId']); $result = $this->storedPaymentMeanProvider->fromRequest($request->reveal()); self::assertNull($result); } + + /** @test */ + public function it_will_return_the_stored_method_id_from_a_combined_id_param(): void + { + $request = $this->prophesize(Enlight_Controller_Request_Request::class); + $request->getParam('register', [])->willReturn(['payment' => 'umbrellaId_'.($expectedId = 'storedMethodId')]); + + $result = $this->storedPaymentMeanProvider->fromRequest($request->reveal()); + + self::assertEquals($expectedId, $result); + } } diff --git a/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php b/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php index 3176137b..6e9aeb70 100644 --- a/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php +++ b/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php @@ -6,7 +6,6 @@ use AdyenPayment\Components\Adyen\PaymentMethod\StoredPaymentMeanProviderInterface; use AdyenPayment\Components\Manager\UserPreferenceManagerInterface; -use AdyenPayment\Models\Payment\PaymentMean; use AdyenPayment\Models\UserPreference; use AdyenPayment\Subscriber\Account\SaveStoredMethodPreferenceSubscriber; use Doctrine\ORM\EntityRepository; @@ -158,11 +157,7 @@ public function it_will_save_the_user_preferences_with_param_value(): void 'payment' => 'proper_'.($storedMethodId = 'storedMethodId'), ]); $this->args->getRequest()->willReturn($this->request->reveal()); - $storedPaymentMean = PaymentMean::createFromShopwareArray([ - 'source' => 'any', - 'stored_method_id' => $storedMethodId, - ]); - $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedPaymentMean); + $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedMethodId); $userPreference = new UserPreference(); $userPreference->setUserId($userId); @@ -183,11 +178,7 @@ public function it_will_update_the_user_preferences_with_param_value(): void 'payment' => 'proper_'.($storedMethodId = 'storedMethodId'), ]); $this->args->getRequest()->willReturn($this->request->reveal()); - $storedPaymentMean = PaymentMean::createFromShopwareArray([ - 'source' => 'any', - 'stored_method_id' => $storedMethodId, - ]); - $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedPaymentMean); + $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedMethodId); $userPreference = new UserPreference(); $userPreference->setId(123); diff --git a/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php index 92b20638..654c2993 100644 --- a/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php +++ b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php @@ -10,10 +10,12 @@ use Doctrine\ORM\EntityRepository; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; +use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; final class EnrichUserPreferenceSubscriberTest extends SubscriberTestCase { + use ProphecyTrait; private EnrichUserPreferenceSubscriber $subscriber; /** @var Enlight_Components_Session_Namespace|ObjectProphecy */ From cdcbb96af26aef21187d37bf005a7e7423e7b381 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 4 Feb 2022 08:31:07 +0100 Subject: [PATCH 057/136] ASW-461 - Single fetch fix --- .../StoredPaymentMeanProvider.php | 36 ++++++++++++++-- .../StoredPaymentMeanProviderInterface.php | 3 +- Resources/services/providers.xml | 5 ++- .../SaveStoredMethodPreferenceSubscriber.php | 3 +- .../StoredPaymentMeanProviderTest.php | 43 +++++++++++-------- ...veStoredMethodPreferenceSubscriberTest.php | 13 +++++- 6 files changed, 77 insertions(+), 26 deletions(-) diff --git a/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php index dfe6f4b9..0b8a06f5 100644 --- a/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php @@ -4,20 +4,48 @@ namespace AdyenPayment\Components\Adyen\PaymentMethod; +use AdyenPayment\AdyenPayment; +use AdyenPayment\Collection\Payment\PaymentMeanCollection; +use AdyenPayment\Models\Payment\PaymentMean; +use Doctrine\DBAL\Connection; use Enlight_Controller_Request_Request; final class StoredPaymentMeanProvider implements StoredPaymentMeanProviderInterface { - public function fromRequest(Enlight_Controller_Request_Request $request): ?string + private EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider; + private Connection $connection; + + public function __construct( + EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider, + Connection $connection + ) { + $this->enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + $this->connection = $connection; + } + + public function fromRequest(Enlight_Controller_Request_Request $request): ?PaymentMean { $registerPayment = $request->getParam('register', [])['payment'] ?? null; if (null === $registerPayment) { return null; } - // at this point the payment param will be the combined id: [SW umbrella ID] + _ + [Adyen stored method ID] - $splitMethod = explode('_', $registerPayment); + $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( + PaymentMeanCollection::createFromShopwareArray($this->fetchUmbrellaMethod()) + ); + + return $enrichedPaymentMeans->fetchByUmbrellaStoredMethodId($registerPayment); + } + + private function fetchUmbrellaMethod(): array + { + $queryBuilder = $this->connection->createQueryBuilder(); - return 1 < count($splitMethod) ? $splitMethod[1] : null; + return $queryBuilder->select('*') + ->from('s_core_paymentmeans') + ->where('name = :umbrellaMethodName') + ->setParameter(':umbrellaMethodName', AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE) + ->execute() + ->fetchAll(); } } diff --git a/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php b/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php index 72ddab19..e7ade33a 100644 --- a/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php +++ b/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php @@ -4,9 +4,10 @@ namespace AdyenPayment\Components\Adyen\PaymentMethod; +use AdyenPayment\Models\Payment\PaymentMean; use Enlight_Controller_Request_Request; interface StoredPaymentMeanProviderInterface { - public function fromRequest(Enlight_Controller_Request_Request $request): ?string; + public function fromRequest(Enlight_Controller_Request_Request $request): ?PaymentMean; } diff --git a/Resources/services/providers.xml b/Resources/services/providers.xml index e238f9e3..5c7267d2 100644 --- a/Resources/services/providers.xml +++ b/Resources/services/providers.xml @@ -8,7 +8,10 @@ - + + + + diff --git a/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php b/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php index b30d6d3e..9f4fee65 100644 --- a/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php +++ b/Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php @@ -49,7 +49,8 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void return; } - $storedMethodId = $this->storedPaymentMeanProvider->fromRequest($request); + $storedMethod = $this->storedPaymentMeanProvider->fromRequest($request); + $storedMethodId = null !== $storedMethod ? $storedMethod->getValue('stored_method_id') : null; $userPreference = $this->userPreferenceRepository->findOneBy(['userId' => $userId]); if (null === $userPreference) { diff --git a/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php index 1ecf539c..8043db3e 100644 --- a/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php +++ b/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php @@ -4,10 +4,14 @@ namespace AdyenPayment\Tests\Unit\Components\Adyen\PaymentMethod; +use AdyenPayment\AdyenPayment; +use AdyenPayment\Collection\Payment\PaymentMeanCollection; use AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProviderInterface; use AdyenPayment\Components\Adyen\PaymentMethod\StoredPaymentMeanProvider; use AdyenPayment\Components\Adyen\PaymentMethod\StoredPaymentMeanProviderInterface; -use AdyenPayment\Shopware\Provider\PaymentMeansProviderInterface; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\ForwardCompatibility\DriverResultStatement; +use Doctrine\DBAL\Query\QueryBuilder; use Enlight_Controller_Request_Request; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; @@ -21,15 +25,18 @@ final class StoredPaymentMeanProviderTest extends TestCase /** @var EnrichedPaymentMeanProviderInterface|ObjectProphecy */ private $enrichedPaymentMeanProvider; - /** @var ObjectProphecy|PaymentMeansProviderInterface */ - private $paymentMeansProvider; + /** @var Connection|ObjectProphecy */ + private $connection; protected function setUp(): void { $this->enrichedPaymentMeanProvider = $this->prophesize(EnrichedPaymentMeanProviderInterface::class); - $this->paymentMeansProvider = $this->prophesize(PaymentMeansProviderInterface::class); + $this->connection = $this->prophesize(Connection::class); - $this->storedPaymentMeanProvider = new StoredPaymentMeanProvider(); + $this->storedPaymentMeanProvider = new StoredPaymentMeanProvider( + $this->enrichedPaymentMeanProvider->reveal(), + $this->connection->reveal(), + ); } /** @test */ @@ -50,24 +57,26 @@ public function it_will_return_null_on_missing_params(): void } /** @test */ - public function it_will_return_null_on_none_combined_id_param(): void + public function it_will_try_to_provide_a_payment_by_umbrella_stored_method_id(): void { $request = $this->prophesize(Enlight_Controller_Request_Request::class); - $request->getParam('register', [])->willReturn(['payment' => $id = 'anyPaymentId']); + $request->getParam('register', [])->willReturn(['payment' => $id = 'stored_method_umbrella_id']); - $result = $this->storedPaymentMeanProvider->fromRequest($request->reveal()); - - self::assertNull($result); - } + $emptyCollection = PaymentMeanCollection::createFromShopwareArray([]); + $this->enrichedPaymentMeanProvider->__invoke($emptyCollection)->willReturn($emptyCollection); + $queryBuilder = $this->prophesize(QueryBuilder::class); + $queryBuilder->select('*')->willReturn($queryBuilder); + $queryBuilder->from('s_core_paymentmeans')->willReturn($queryBuilder); + $queryBuilder->where('name = :umbrellaMethodName')->willReturn($queryBuilder); + $queryBuilder->setParameter(':umbrellaMethodName', AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE)->willReturn($queryBuilder); + $driverResultStatement = $this->prophesize(DriverResultStatement::class); + $driverResultStatement->fetchAll()->willReturn([]); - /** @test */ - public function it_will_return_the_stored_method_id_from_a_combined_id_param(): void - { - $request = $this->prophesize(Enlight_Controller_Request_Request::class); - $request->getParam('register', [])->willReturn(['payment' => 'umbrellaId_'.($expectedId = 'storedMethodId')]); + $queryBuilder->execute()->willReturn($driverResultStatement->reveal()); + $this->connection->createQueryBuilder()->willReturn($queryBuilder->reveal()); $result = $this->storedPaymentMeanProvider->fromRequest($request->reveal()); - self::assertEquals($expectedId, $result); + self::assertNull($result); } } diff --git a/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php b/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php index 6e9aeb70..3176137b 100644 --- a/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php +++ b/tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php @@ -6,6 +6,7 @@ use AdyenPayment\Components\Adyen\PaymentMethod\StoredPaymentMeanProviderInterface; use AdyenPayment\Components\Manager\UserPreferenceManagerInterface; +use AdyenPayment\Models\Payment\PaymentMean; use AdyenPayment\Models\UserPreference; use AdyenPayment\Subscriber\Account\SaveStoredMethodPreferenceSubscriber; use Doctrine\ORM\EntityRepository; @@ -157,7 +158,11 @@ public function it_will_save_the_user_preferences_with_param_value(): void 'payment' => 'proper_'.($storedMethodId = 'storedMethodId'), ]); $this->args->getRequest()->willReturn($this->request->reveal()); - $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedMethodId); + $storedPaymentMean = PaymentMean::createFromShopwareArray([ + 'source' => 'any', + 'stored_method_id' => $storedMethodId, + ]); + $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedPaymentMean); $userPreference = new UserPreference(); $userPreference->setUserId($userId); @@ -178,7 +183,11 @@ public function it_will_update_the_user_preferences_with_param_value(): void 'payment' => 'proper_'.($storedMethodId = 'storedMethodId'), ]); $this->args->getRequest()->willReturn($this->request->reveal()); - $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedMethodId); + $storedPaymentMean = PaymentMean::createFromShopwareArray([ + 'source' => 'any', + 'stored_method_id' => $storedMethodId, + ]); + $this->storedPaymentMeanProvider->fromRequest($this->request->reveal())->willReturn($storedPaymentMean); $userPreference = new UserPreference(); $userPreference->setId(123); From cf900362979d9c59ad7b956e9e93cae01f77d65c Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 7 Feb 2022 10:08:32 +0100 Subject: [PATCH 058/136] ASW-466 - Guests fix --- Models/PaymentInfo.php | 2 +- Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php | 4 ++-- .../Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Models/PaymentInfo.php b/Models/PaymentInfo.php index 5b6903ff..709d58eb 100644 --- a/Models/PaymentInfo.php +++ b/Models/PaymentInfo.php @@ -291,7 +291,7 @@ public function getStoredMethodId(): string return (string) $this->storedMethodId; } - public function setStoredMethodId(string $storedMethodId): self + public function setStoredMethodId(?string $storedMethodId): self { $this->storedMethodId = $storedMethodId; diff --git a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php index 48278541..82889f3c 100644 --- a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php +++ b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php @@ -6,7 +6,6 @@ use AdyenPayment\AdyenPayment; use AdyenPayment\Collection\Payment\PaymentMeanCollection; -use AdyenPayment\Exceptions\UmbrellaPaymentMeanNotFoundException; use AdyenPayment\Shopware\Provider\PaymentMeansProviderInterface; use Enlight\Event\SubscriberInterface; use Enlight_Components_Session_Namespace; @@ -51,7 +50,8 @@ public function __invoke(\Enlight_Controller_ActionEventArgs $args): void $umbrellaPayment = $enrichedPaymentMeans->fetchStoredMethodUmbrellaPaymentMean(); if (null === $umbrellaPayment) { - throw UmbrellaPaymentMeanNotFoundException::missingUmbrellaPaymentMean(); + // guest user won't have stored method + return; } // but if the umbrella payment is in the user data it means a stored method was preselected by the user if ($umbrellaPayment->getId() !== (int) $preselectedPaymentId) { diff --git a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php index ccb9dcd8..61b0b753 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -5,7 +5,6 @@ namespace AdyenPayment\Tests\Unit\Subscriber\Checkout; use AdyenPayment\AdyenPayment; -use AdyenPayment\Exceptions\UmbrellaPaymentMeanNotFoundException; use AdyenPayment\Shopware\Provider\PaymentMeansProviderInterface; use AdyenPayment\Subscriber\Checkout\EnrichUmbrellaPaymentMeanSubscriber; use AdyenPayment\Tests\Unit\Subscriber\SubscriberTestCase; @@ -92,7 +91,6 @@ public function it_throws_an_exception_on_missing_missing_umbrella_method_for_pr $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn(null); $this->paymentMeansProvider->__invoke()->willReturn([]); - self::expectException(UmbrellaPaymentMeanNotFoundException::class); $this->subscriber->__invoke($eventArgs); self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); From 04462f56b1e94460867b451a271fb019a321531d Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 7 Feb 2022 10:13:47 +0100 Subject: [PATCH 059/136] ASW-466 - Fix type --- Models/PaymentInfo.php | 2 +- Subscriber/AddStoredMethodIdOnOrderSubscriber.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Models/PaymentInfo.php b/Models/PaymentInfo.php index 709d58eb..5b6903ff 100644 --- a/Models/PaymentInfo.php +++ b/Models/PaymentInfo.php @@ -291,7 +291,7 @@ public function getStoredMethodId(): string return (string) $this->storedMethodId; } - public function setStoredMethodId(?string $storedMethodId): self + public function setStoredMethodId(string $storedMethodId): self { $this->storedMethodId = $storedMethodId; diff --git a/Subscriber/AddStoredMethodIdOnOrderSubscriber.php b/Subscriber/AddStoredMethodIdOnOrderSubscriber.php index 51de9fca..e5a86bde 100644 --- a/Subscriber/AddStoredMethodIdOnOrderSubscriber.php +++ b/Subscriber/AddStoredMethodIdOnOrderSubscriber.php @@ -30,7 +30,7 @@ public static function getSubscribedEvents() public function persistPaymentInfoStoredMethodId(Enlight_Event_EventArgs $args) { $paymentInfoId = Shopware()->Session()->get(AdyenPayment::SESSION_ADYEN_PAYMENT_INFO_ID); - $storedMethodId = Shopware()->Session()->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); + $storedMethodId = Shopware()->Session()->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, ''); if (null === $paymentInfoId) { return $args->getReturn(); From 9f294284b6b4594da6713f4a278d6123f3f77ec4 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 7 Feb 2022 10:15:45 +0100 Subject: [PATCH 060/136] ASW-466 - Test name fix --- .../Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php index 61b0b753..329f60f8 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -82,7 +82,7 @@ public function it_does_nothing_on_missing_session_and_none_preselected_stored_m } /** @test */ - public function it_throws_an_exception_on_missing_missing_umbrella_method_for_preselected_payment(): void + public function it_does_nothing_on_missing_missing_umbrella_method_for_preselected_payment(): void { $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = [ 'sUserData' => ['additional' => ['payment' => ['id' => 'preselectedPaymentId']]], From 604c027619f44faab299ac0bc2305e6ff6409b92 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 7 Feb 2022 10:33:59 +0100 Subject: [PATCH 061/136] ASW-466 - CR fix --- Resources/services/subscribers.xml | 1 + Subscriber/AddStoredMethodIdOnOrderSubscriber.php | 9 ++++++--- .../Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Resources/services/subscribers.xml b/Resources/services/subscribers.xml index ef8afb28..a05c526f 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -56,6 +56,7 @@ + diff --git a/Subscriber/AddStoredMethodIdOnOrderSubscriber.php b/Subscriber/AddStoredMethodIdOnOrderSubscriber.php index e5a86bde..70c39c92 100644 --- a/Subscriber/AddStoredMethodIdOnOrderSubscriber.php +++ b/Subscriber/AddStoredMethodIdOnOrderSubscriber.php @@ -8,6 +8,7 @@ use AdyenPayment\Models\PaymentInfo; use Doctrine\Persistence\ObjectRepository; use Enlight\Event\SubscriberInterface; +use Enlight_Components_Session_Namespace; use Enlight_Event_EventArgs; use Shopware\Components\Model\ModelManager; @@ -15,11 +16,13 @@ final class AddStoredMethodIdOnOrderSubscriber implements SubscriberInterface { private ModelManager $modelManager; private ObjectRepository $paymentInfoRepository; + private Enlight_Components_Session_Namespace $session; - public function __construct(ModelManager $modelManager) + public function __construct(ModelManager $modelManager, Enlight_Components_Session_Namespace $session) { $this->modelManager = $modelManager; $this->paymentInfoRepository = $this->modelManager->getRepository(PaymentInfo::class); + $this->session = $session; } public static function getSubscribedEvents() @@ -29,8 +32,8 @@ public static function getSubscribedEvents() public function persistPaymentInfoStoredMethodId(Enlight_Event_EventArgs $args) { - $paymentInfoId = Shopware()->Session()->get(AdyenPayment::SESSION_ADYEN_PAYMENT_INFO_ID); - $storedMethodId = Shopware()->Session()->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, ''); + $paymentInfoId = $this->session->get(AdyenPayment::SESSION_ADYEN_PAYMENT_INFO_ID); + $storedMethodId = (string) $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, ''); if (null === $paymentInfoId) { return $args->getReturn(); diff --git a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php index 329f60f8..f6a4bcf6 100644 --- a/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -82,7 +82,7 @@ public function it_does_nothing_on_missing_session_and_none_preselected_stored_m } /** @test */ - public function it_does_nothing_on_missing_missing_umbrella_method_for_preselected_payment(): void + public function it_does_nothing_on_missing_umbrella_method_for_preselected_payment(): void { $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = [ 'sUserData' => ['additional' => ['payment' => ['id' => 'preselectedPaymentId']]], From 7c80f3295e5929e6f2809b77306f94c4a838aa91 Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Tue, 8 Feb 2022 14:23:23 +0100 Subject: [PATCH 062/136] ASW-0 Bump version 3.3.1 --- Resources/services/applepay-merchant.xml | 2 +- plugin.xml | 10 +++++++++- ...developer-merchantid-domain-association.archive} | Bin 3 files changed, 10 insertions(+), 2 deletions(-) rename storage/{apple-developer-merchantid-domain-association.zip => apple-developer-merchantid-domain-association.archive} (100%) diff --git a/Resources/services/applepay-merchant.xml b/Resources/services/applepay-merchant.xml index 087e2027..7281a0f2 100644 --- a/Resources/services/applepay-merchant.xml +++ b/Resources/services/applepay-merchant.xml @@ -6,7 +6,7 @@ https://eu.adyen.link %kernel.project_dir%/.well-known/apple-developer-merchantid-domain-association - %adyen_payment.plugin_dir%/storage/apple-developer-merchantid-domain-association.zip + %adyen_payment.plugin_dir%/storage/apple-developer-merchantid-domain-association.archive diff --git a/plugin.xml b/plugin.xml index 1117f3f8..894a61b5 100644 --- a/plugin.xml +++ b/plugin.xml @@ -4,7 +4,7 @@ - 3.3.0 + 3.3.1 Adyen Adyen https://adyen.com @@ -289,4 +289,12 @@ Plugin compatibility with SwagPayPal + + + Same release as 3.3.0, but alternate working for archive file + + + Same release as 3.3.0, but alternate working for archive file + + diff --git a/storage/apple-developer-merchantid-domain-association.zip b/storage/apple-developer-merchantid-domain-association.archive similarity index 100% rename from storage/apple-developer-merchantid-domain-association.zip rename to storage/apple-developer-merchantid-domain-association.archive From 1c2f06c75009e28a167f2b87bdc5dc1db9059fcb Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Tue, 8 Feb 2022 14:57:38 +0100 Subject: [PATCH 063/136] ASW-0 Bump version 3.4.0, changelog --- plugin.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugin.xml b/plugin.xml index 894a61b5..a52fa3ea 100644 --- a/plugin.xml +++ b/plugin.xml @@ -4,7 +4,7 @@ - 3.3.1 + 3.4.0 Adyen Adyen https://adyen.com @@ -297,4 +297,12 @@ Same release as 3.3.0, but alternate working for archive file + + + Enable Adyen's stored payment methods feature + + + Enable Adyen's stored payment methods feature + + From 4492131a03a726666f2a40b441cfb8241488734f Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Tue, 8 Feb 2022 15:21:32 +0100 Subject: [PATCH 064/136] ASW-0 bump version 3.5.0 --- plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.xml b/plugin.xml index a52fa3ea..1ff24f10 100644 --- a/plugin.xml +++ b/plugin.xml @@ -4,7 +4,7 @@ - 3.4.0 + 3.5.0 Adyen Adyen https://adyen.com From ebda6ce274176041567991d14274f63185ddd5d8 Mon Sep 17 00:00:00 2001 From: davebueds Date: Mon, 14 Feb 2022 15:41:20 +0100 Subject: [PATCH 065/136] ASW-476 refactor result codes, add result code handler, add tests, refactor --- Components/Adyen/PaymentResultCodeHandler.php | 34 ++++++ .../PaymentResultCodeHandlerInterface.php | 10 ++ Controllers/Frontend/Adyen.php | 81 +++---------- Controllers/Frontend/Process.php | 43 +++---- Models/Enum/PaymentResultCodes.php | 18 --- Models/PaymentResultCodes.php | 106 ++++++++++++++++++ Resources/services/components.xml | 3 + .../Adyen/PaymentResultCodeHandlerTest.php | 84 ++++++++++++++ tests/Unit/Models/PaymentResultCodesTest.php | 39 +++++++ 9 files changed, 311 insertions(+), 107 deletions(-) create mode 100644 Components/Adyen/PaymentResultCodeHandler.php create mode 100644 Components/Adyen/PaymentResultCodeHandlerInterface.php delete mode 100644 Models/Enum/PaymentResultCodes.php create mode 100644 Models/PaymentResultCodes.php create mode 100644 tests/Unit/Components/Adyen/PaymentResultCodeHandlerTest.php create mode 100644 tests/Unit/Models/PaymentResultCodesTest.php diff --git a/Components/Adyen/PaymentResultCodeHandler.php b/Components/Adyen/PaymentResultCodeHandler.php new file mode 100644 index 00000000..c9f502c2 --- /dev/null +++ b/Components/Adyen/PaymentResultCodeHandler.php @@ -0,0 +1,34 @@ +basketService = $basketService; + } + + public function __invoke(array $paymentResponseInfo): void + { + try { + PaymentResultCodes::load($paymentResponseInfo['resultCode']); + } catch (\InvalidArgumentException $exception) { + $this->handlePaymentDataError($paymentResponseInfo); + } + } + + private function handlePaymentDataError(array $paymentResponseInfo): void + { + if (isset($paymentResponseInfo['merchantReference'])) { + $this->basketService->cancelAndRestoreByOrderNumber($paymentResponseInfo['merchantReference']); + } + } +} diff --git a/Components/Adyen/PaymentResultCodeHandlerInterface.php b/Components/Adyen/PaymentResultCodeHandlerInterface.php new file mode 100644 index 00000000..dcc64f86 --- /dev/null +++ b/Components/Adyen/PaymentResultCodeHandlerInterface.php @@ -0,0 +1,10 @@ +adyenManager = $this->get('AdyenPayment\Components\Manager\AdyenManager'); - $this->adyenCheckout = $this->get('AdyenPayment\Components\Adyen\PaymentMethodService'); - $this->basketService = $this->get('AdyenPayment\Components\BasketService'); + $this->adyenManager = $this->get(AdyenManager::class); + $this->adyenCheckout = $this->get(PaymentMethodService::class); $this->logger = $this->get('adyen_payment.logger'); - $this->paymentPayloadProvider = $this->get('AdyenPayment\Components\Payload\PaymentPayloadProvider'); + $this->paymentPayloadProvider = $this->get(PaymentPayloadProvider::class); + $this->paymentResultCodeHandler = $this->get(PaymentResultCodeHandlerInterface::class); } public function ajaxDoPaymentAction(): void @@ -71,7 +53,7 @@ public function ajaxDoPaymentAction(): void $context->getTransaction(), $paymentInfo['paymentData'] ?? '' ); - $this->handlePaymentData($paymentInfo); + ($this->paymentResultCodeHandler)($paymentInfo); $this->Response()->setBody(json_encode( [ @@ -127,7 +109,7 @@ public function paymentDetailsAction(): void $payload = array_intersect_key($this->Request()->getPost(), ['details' => true]); $checkout = $this->adyenCheckout->getCheckout(); $paymentInfo = $checkout->paymentsDetails($payload); - $this->handlePaymentData($paymentInfo); + ($this->paymentResultCodeHandler)($paymentInfo); $this->Response()->setBody(json_encode($paymentInfo)); } @@ -234,41 +216,4 @@ private function getShopperInfo(): array 'shopperIP' => $this->request->getClientIp(), ]; } - - - /** - * @param $paymentInfo - * - * @throws Enlight_Event_Exception - * @throws Enlight_Exception - * @throws Zend_Db_Adapter_Exception - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\OptimisticLockException - */ - private function handlePaymentData($paymentInfo): void - { - if (!in_array( - $paymentInfo['resultCode'], - ['Authorised', 'IdentifyShopper', 'ChallengeShopper', 'RedirectShopper'] - ) - ) { - $this->handlePaymentDataError($paymentInfo); - } - } - - /** - * @param $paymentInfo - * - * @throws Enlight_Event_Exception - * @throws Enlight_Exception - * @throws Zend_Db_Adapter_Exception - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\OptimisticLockException - */ - private function handlePaymentDataError($paymentInfo): void - { - if ($paymentInfo['merchantReference']) { - $this->basketService->cancelAndRestoreByOrderNumber($paymentInfo['merchantReference']); - } - } } diff --git a/Controllers/Frontend/Process.php b/Controllers/Frontend/Process.php index c79dc4eb..3e79894f 100644 --- a/Controllers/Frontend/Process.php +++ b/Controllers/Frontend/Process.php @@ -6,7 +6,8 @@ use AdyenPayment\Components\Manager\AdyenManager; use AdyenPayment\Components\Manager\OrderManagerInterface; use AdyenPayment\Components\OrderMailService; -use AdyenPayment\Models\Enum\PaymentResultCodes; +use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Session\ErrorMessageProvider; use AdyenPayment\Session\MessageProvider; use AdyenPayment\Utils\RequestDataFormatter; use Shopware\Components\CSRFWhitelistAware; @@ -43,14 +44,14 @@ public function getWhitelistedCSRFActions() */ public function preDispatch() { - $this->adyenManager = $this->get('AdyenPayment\Components\Manager\AdyenManager'); - $this->adyenCheckout = $this->get('AdyenPayment\Components\Adyen\PaymentMethodService'); - $this->basketService = $this->get('AdyenPayment\Components\BasketService'); - $this->orderMailService = $this->get('AdyenPayment\Components\OrderMailService'); + $this->adyenManager = $this->get(AdyenManager::class); + $this->adyenCheckout = $this->get(PaymentMethodService::class); + $this->basketService = $this->get(BasketService::class); + $this->orderMailService = $this->get(OrderMailService::class); $this->logger = $this->get('adyen_payment.logger'); - $this->orderManager = $this->get('AdyenPayment\Components\Manager\OrderManager'); + $this->orderManager = $this->get(OrderManagerInterface::class); $this->snippets = $this->get('snippets'); - $this->errorMessageProvider = $this->get('AdyenPayment\Session\ErrorMessageProvider'); + $this->errorMessageProvider = $this->get(ErrorMessageProvider::class); } /** @@ -70,10 +71,10 @@ public function returnAction(): void $result = $this->validateResponse($response, $order); $this->handleReturnResult($result, $order); - switch ($result['resultCode']) { - case PaymentResultCodes::AUTHORISED: - case PaymentResultCodes::PENDING: - case PaymentResultCodes::RECEIVED: + switch(PaymentResultCodes::load($result['resultCode'])) { + case PaymentResultCodes::authorised(): + case PaymentResultCodes::pending(): + case PaymentResultCodes::received(): if (!empty($result['merchantReference'])) { $this->orderMailService->sendOrderConfirmationMail($result['merchantReference']); } @@ -84,9 +85,9 @@ public function returnAction(): void 'sAGB' => true, ]); break; - case PaymentResultCodes::CANCELLED: - case PaymentResultCodes::ERROR: - case PaymentResultCodes::REFUSED: + case PaymentResultCodes::cancelled(): + case PaymentResultCodes::error(): + case PaymentResultCodes::refused(): default: $this->errorMessageProvider->add( $this->snippets->getNamespace('adyen/checkout/error') @@ -121,18 +122,18 @@ private function handleReturnResult(array $result, ?Order $order): void return; } - switch ($result['resultCode']) { - case PaymentResultCodes::AUTHORISED: - case PaymentResultCodes::PENDING: - case PaymentResultCodes::RECEIVED: + switch (PaymentResultCodes::load($result['resultCode'])) { + case PaymentResultCodes::authorised(): + case PaymentResultCodes::pending(): + case PaymentResultCodes::received(): $paymentStatus = $this->getModelManager()->find( Status::class, Status::PAYMENT_STATE_THE_PAYMENT_HAS_BEEN_ORDERED ); break; - case PaymentResultCodes::CANCELLED: - case PaymentResultCodes::ERROR: - case PaymentResultCodes::REFUSED: + case PaymentResultCodes::cancelled(): + case PaymentResultCodes::error(): + case PaymentResultCodes::refused(): $paymentStatus = $this->getModelManager()->find( Status::class, Status::PAYMENT_STATE_THE_PROCESS_HAS_BEEN_CANCELLED diff --git a/Models/Enum/PaymentResultCodes.php b/Models/Enum/PaymentResultCodes.php deleted file mode 100644 index 11b78062..00000000 --- a/Models/Enum/PaymentResultCodes.php +++ /dev/null @@ -1,18 +0,0 @@ -availableResultCodes(), true)) { + throw new \InvalidArgumentException('Invalid result code: "'.$resultCode.'"'); + } + + $this->resultCode = $resultCode; + } + + public function resultCode(): string + { + return $this->resultCode; + } + + public function equals(PaymentResultCodes $paymentResultCodes): bool + { + return $paymentResultCodes->resultCode() === $this->resultCode; + } + + public static function load(string $resultCode): self + { + return new self($resultCode); + } + + /** + * @return array + */ + private function availableResultCodes(): array + { + return [ + self::AUTHORISED, + self::CANCELLED, + self::CHALLENGESHOPPER, + self::ERROR, + self::IDENTIFYSHOPPER, + self::PENDING, + self::RECEIVED, + self::REDIRECTSHOPPER, + self::REFUSED, + ]; + } + + public static function authorised(): self + { + return new self(self::AUTHORISED); + } + + public static function challengeShopper(): self + { + return new self(self::CHALLENGESHOPPER); + } + + public static function cancelled(): self + { + return new self(self::CANCELLED); + } + + public static function error(): self + { + return new self(self::ERROR); + } + + public static function identifyShopper(): self + { + return new self(self::IDENTIFYSHOPPER); + } + + public static function pending(): self + { + return new self(self::PENDING); + } + + public static function received(): self + { + return new self(self::RECEIVED); + } + + public static function redirectShopper(): self + { + return new self(self::REDIRECTSHOPPER); + } + + public static function refused(): self + { + return new self(self::REFUSED); + } +} diff --git a/Resources/services/components.xml b/Resources/services/components.xml index 94f57b34..621e0c50 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -178,5 +178,8 @@ + + + diff --git a/tests/Unit/Components/Adyen/PaymentResultCodeHandlerTest.php b/tests/Unit/Components/Adyen/PaymentResultCodeHandlerTest.php new file mode 100644 index 00000000..046d62d1 --- /dev/null +++ b/tests/Unit/Components/Adyen/PaymentResultCodeHandlerTest.php @@ -0,0 +1,84 @@ +basketService = $this->prophesize(BasketService::class); + $this->paymentResultCodeHandler = new PaymentResultCodeHandler( + $this->basketService->reveal() + ); + } + + /** @test */ + public function it_is_instance_of_payment_result_code_handler_interface(): void + { + $this->assertInstanceOf( + PaymentResultCodeHandlerInterface::class, + $this->paymentResultCodeHandler + ); + } + + /** + * @dataProvider paymentResponseInfoProvider + * @test + */ + public function it_can_handle_a_known_payment_result_code(array $paymentResponseInfo): void + { + ($this->paymentResultCodeHandler)($paymentResponseInfo); + $this->basketService->cancelAndRestoreByOrderNumber(Argument::cetera())->shouldNotBeCalled(); + } + + public function paymentResponseInfoProvider(): \Generator + { + yield [['resultCode' => PaymentResultCodes::authorised()->resultCode()]]; + yield [['resultCode' => PaymentResultCodes::cancelled()->resultCode()]]; + yield [['resultCode' => PaymentResultCodes::challengeShopper()->resultCode()]]; + yield [['resultCode' => PaymentResultCodes::error()->resultCode()]]; + yield [['resultCode' => PaymentResultCodes::identifyShopper()->resultCode()]]; + yield [['resultCode' => PaymentResultCodes::pending()->resultCode()]]; + yield [['resultCode' => PaymentResultCodes::received()->resultCode()]]; + yield [['resultCode' => PaymentResultCodes::redirectShopper()->resultCode()]]; + yield [['resultCode' => PaymentResultCodes::refused()->resultCode()]]; + } + + /** @test */ + public function it_will_cancel_and_restore_order_number_when_merchant_reference_is_given(): void + { + $paymentResponseInfo = [ + 'resultCode' => 'NOT_KNOWN_RESULT_CODE', + 'merchantReference' => '012345', + ]; + ($this->paymentResultCodeHandler)($paymentResponseInfo); + $this->basketService->cancelAndRestoreByOrderNumber($paymentResponseInfo['merchantReference'])->shouldBeCalledOnce(); + } + + /** @test */ + public function it_will_not_cancel_and_restore_order_number_when_no_merchant_reference_is_given(): void + { + $paymentResponseInfo = [ + 'resultCode' => 'NOT_KNOWN_RESULT_CODE', + ]; + ($this->paymentResultCodeHandler)($paymentResponseInfo); + $this->basketService->cancelAndRestoreByOrderNumber(Argument::cetera())->shouldNotBeCalled(); + } +} diff --git a/tests/Unit/Models/PaymentResultCodesTest.php b/tests/Unit/Models/PaymentResultCodesTest.php new file mode 100644 index 00000000..941ad065 --- /dev/null +++ b/tests/Unit/Models/PaymentResultCodesTest.php @@ -0,0 +1,39 @@ +assertInstanceOf(PaymentResultCodes::class, PaymentResultCodes::authorised()); + } + + /** + * @dataProvider resultCodeProvider + * @test + */ + public function it_contains_result_code(PaymentResultCodes $resultCode, string $code): void + { + $this->assertEquals($code, $resultCode->resultCode()); + } + + public function resultCodeProvider(): \Generator + { + yield [PaymentResultCodes::authorised(), 'Authorised']; + yield [PaymentResultCodes::cancelled(), 'Cancelled']; + yield [PaymentResultCodes::challengeShopper(), 'ChallengeShopper']; + yield [PaymentResultCodes::error(), 'Error']; + yield [PaymentResultCodes::identifyShopper(), 'IdentifyShopper']; + yield [PaymentResultCodes::pending(), 'Pending']; + yield [PaymentResultCodes::received(), 'Received']; + yield [PaymentResultCodes::redirectShopper(), 'RedirectShopper']; + yield [PaymentResultCodes::refused(), 'Refused']; + } +} From 30a8a3cc5a3db9f21e54d18c7eb47cd86916994e Mon Sep 17 00:00:00 2001 From: davebueds Date: Mon, 14 Feb 2022 17:10:49 +0100 Subject: [PATCH 066/136] ASW-472 add model ShopperInteraction and test --- .../RecurringPayment/ShopperInteraction.php | 54 ++++++++++++++++ .../ShopperInteractionTest.php | 62 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 Models/RecurringPayment/ShopperInteraction.php create mode 100644 tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php diff --git a/Models/RecurringPayment/ShopperInteraction.php b/Models/RecurringPayment/ShopperInteraction.php new file mode 100644 index 00000000..beffae1d --- /dev/null +++ b/Models/RecurringPayment/ShopperInteraction.php @@ -0,0 +1,54 @@ +availableShopperInteractions(), true)) { + throw new \InvalidArgumentException('Invalid shopper interaction: "'.$shopperInteraction.'"'); + } + + $this->value = $shopperInteraction; + } + + public function value(): string + { + return $this->value; + } + + public function equals(ShopperInteraction $paymentShopperInteraction): bool + { + return $paymentShopperInteraction->value() === $this->value; + } + + public static function load(string $shopperInteraction): self + { + return new self($shopperInteraction); + } + + private function availableShopperInteractions(): array + { + return [ + self::CONTAUTH, + self::ECOMMERCE, + ]; + } + + public static function contAuth(): self + { + return new self(self::CONTAUTH); + } + + public static function ecommerce(): self + { + return new self(self::ECOMMERCE); + } +} diff --git a/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php b/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php new file mode 100644 index 00000000..662d24be --- /dev/null +++ b/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php @@ -0,0 +1,62 @@ +assertInstanceOf(ShopperInteraction::class, ShopperInteraction::contAuth()); + } + + /** + * @dataProvider shopperInteractionProvider + * @test + */ + public function it_contains_shopper_interaction(ShopperInteraction $shopperInteraction, string $expected): void + { + $this->assertEquals($expected, $shopperInteraction->value()); + } + + public function shopperInteractionProvider(): \Generator + { + yield [ShopperInteraction::contAuth(), 'ContAuth']; + yield [ShopperInteraction::ecommerce(), 'Ecommerce']; + } + + /** @test */ + public function it_throws_an_invalid_argument_exception_when_shopper_interaction_is_unknown(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid shopper interaction: "test"'); + + ShopperInteraction::load('test'); + } + + /** @test */ + public function it_can_check_it_is_equal_to_another_value_object(): void + { + $this->assertTrue(ShopperInteraction::ecommerce()->equals(ShopperInteraction::ecommerce())); + } + + /** @test */ + public function it_can_check_it_is_not_equal_to_another_value_object(): void + { + $this->assertFalse(ShopperInteraction::ecommerce()->equals(ShopperInteraction::contAuth())); + } + + /** @test */ + public function it_can_load_a_shopper_interaction(): void + { + $this->assertEquals( + ShopperInteraction::ecommerce(), + ShopperInteraction::load('Ecommerce') + ); + } +} From 655a9705753425d68688c353fcb86a115b2c09bb Mon Sep 17 00:00:00 2001 From: davebueds Date: Mon, 14 Feb 2022 17:18:51 +0100 Subject: [PATCH 067/136] ASW-476 add missing unit test cases --- tests/Unit/Models/PaymentResultCodesTest.php | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/Unit/Models/PaymentResultCodesTest.php b/tests/Unit/Models/PaymentResultCodesTest.php index 941ad065..55f6f35a 100644 --- a/tests/Unit/Models/PaymentResultCodesTest.php +++ b/tests/Unit/Models/PaymentResultCodesTest.php @@ -36,4 +36,34 @@ public function resultCodeProvider(): \Generator yield [PaymentResultCodes::redirectShopper(), 'RedirectShopper']; yield [PaymentResultCodes::refused(), 'Refused']; } + + /** @test */ + public function it_throws_an_invalid_argument_exception_when_result_code_is_unknown(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid result code: "test"'); + + PaymentResultCodes::load('test'); + } + + /** @test */ + public function it_can_check_it_is_equal_to_another_value_object(): void + { + $this->assertTrue(PaymentResultCodes::authorised()->equals(PaymentResultCodes::authorised())); + } + + /** @test */ + public function it_can_check_it_is_not_equal_to_another_value_object(): void + { + $this->assertFalse(PaymentResultCodes::authorised()->equals(PaymentResultCodes::cancelled())); + } + + /** @test */ + public function it_can_load_a_result_code(): void + { + $this->assertEquals( + PaymentResultCodes::authorised(), + PaymentResultCodes::load('Authorised') + ); + } } From 665b8022763e689edd68d5ea9876645a273e2bb4 Mon Sep 17 00:00:00 2001 From: davebueds Date: Mon, 14 Feb 2022 17:48:10 +0100 Subject: [PATCH 068/136] ASW-473 add model RecurringProcessingModel and test --- .../RecurringProcessingModel.php | 54 ++++++++++++++++ .../RecurringProcessingModelTest.php | 63 +++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 Models/RecurringPayment/RecurringProcessingModel.php create mode 100644 tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php diff --git a/Models/RecurringPayment/RecurringProcessingModel.php b/Models/RecurringPayment/RecurringProcessingModel.php new file mode 100644 index 00000000..927a920b --- /dev/null +++ b/Models/RecurringPayment/RecurringProcessingModel.php @@ -0,0 +1,54 @@ +availableRecurringProcessingModels(), true)) { + throw new \InvalidArgumentException('Invalid recurring processing model: "'.$recurringProcessingModel.'"'); + } + + $this->value = $recurringProcessingModel; + } + + public function value(): string + { + return $this->value; + } + + public function equals(RecurringProcessingModel $recurringProcessingModel): bool + { + return $recurringProcessingModel->value() === $this->value; + } + + public static function load(string $recurringProcessingModel): self + { + return new self($recurringProcessingModel); + } + + private function availableRecurringProcessingModels(): array + { + return [ + self::CARDONFILE, + self::SUBSCRIPTION, + ]; + } + + public static function cardOnFile(): self + { + return new self(self::CARDONFILE); + } + + public static function subscription(): self + { + return new self(self::SUBSCRIPTION); + } +} diff --git a/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php b/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php new file mode 100644 index 00000000..7085b847 --- /dev/null +++ b/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php @@ -0,0 +1,63 @@ +assertInstanceOf(RecurringProcessingModel::class, RecurringProcessingModel::cardOnFile()); + } + + /** + * @dataProvider recurringProcessingModelProvider + * @test + */ + public function it_contains_recurring_processing_model( + RecurringProcessingModel $recurringProcessingModel, string $expected + ): void { + $this->assertEquals($expected, $recurringProcessingModel->value()); + } + + public function recurringProcessingModelProvider(): \Generator + { + yield [RecurringProcessingModel::cardOnFile(), 'CardOnFile']; + yield [RecurringProcessingModel::subscription(), 'Subscription']; + } + + /** @test */ + public function it_throws_an_invalid_argument_exception_when_recurring_processing_model_is_unknown(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid recurring processing model: "test"'); + + RecurringProcessingModel::load('test'); + } + + /** @test */ + public function it_can_check_it_is_equal_to_another_value_object(): void + { + $this->assertTrue(RecurringProcessingModel::cardOnFile()->equals(RecurringProcessingModel::cardOnFile())); + } + + /** @test */ + public function it_can_check_it_is_not_equal_to_another_value_object(): void + { + $this->assertFalse(RecurringProcessingModel::cardOnFile()->equals(RecurringProcessingModel::subscription())); + } + + /** @test */ + public function it_can_load_a_recurring_processing_model(): void + { + $this->assertEquals( + RecurringProcessingModel::cardOnFile(), + RecurringProcessingModel::load('CardOnFile') + ); + } +} From 244fad621728979d4427bd1e51263d868a4fbd17 Mon Sep 17 00:00:00 2001 From: davebueds Date: Tue, 15 Feb 2022 10:04:37 +0100 Subject: [PATCH 069/136] ASW-477 add CustomerNumberProvider, test and refactor PaymentMethodService --- Components/Adyen/PaymentMethodService.php | 26 ++---- Resources/services/components.xml | 3 +- Resources/services/shopware.xml | 4 + Shopware/Provider/CustomerNumberProvider.php | 32 +++++++ .../CustomerNumberProviderInterface.php | 10 +++ .../Provider/CustomerNumberProviderTest.php | 87 +++++++++++++++++++ 6 files changed, 139 insertions(+), 23 deletions(-) create mode 100644 Shopware/Provider/CustomerNumberProvider.php create mode 100644 Shopware/Provider/CustomerNumberProviderInterface.php create mode 100644 tests/Unit/Shopware/Provider/CustomerNumberProviderTest.php diff --git a/Components/Adyen/PaymentMethodService.php b/Components/Adyen/PaymentMethodService.php index 0200b269..c2f97b1c 100644 --- a/Components/Adyen/PaymentMethodService.php +++ b/Components/Adyen/PaymentMethodService.php @@ -10,10 +10,8 @@ use AdyenPayment\Collection\Payment\PaymentMethodCollection; use AdyenPayment\Components\Configuration; use AdyenPayment\Models\Enum\Channel; -use Enlight_Components_Session_Namespace; +use AdyenPayment\Shopware\Provider\CustomerNumberProviderInterface; use Psr\Log\LoggerInterface; -use Shopware\Components\Model\ModelManager; -use Shopware\Models\Customer\Customer; final class PaymentMethodService implements PaymentMethodServiceInterface { @@ -23,21 +21,18 @@ final class PaymentMethodService implements PaymentMethodServiceInterface private Configuration $configuration; private array $cache; private LoggerInterface $logger; - private Enlight_Components_Session_Namespace $session; - private ModelManager $modelManager; + private CustomerNumberProviderInterface $customerNumberProvider; public function __construct( ApiClientMap $apiClientMap, Configuration $configuration, LoggerInterface $logger, - Enlight_Components_Session_Namespace $session, - ModelManager $modelManager + CustomerNumberProviderInterface $customerNumberProvider ) { $this->apiClientMap = $apiClientMap; $this->configuration = $configuration; $this->logger = $logger; - $this->session = $session; - $this->modelManager = $modelManager; + $this->customerNumberProvider = $customerNumberProvider; } /** @@ -70,7 +65,7 @@ public function getPaymentMethods( ], 'channel' => Channel::WEB, 'shopperLocale' => $locale, - 'shopperReference' => $this->provideCustomerNumber(), + 'shopperReference' => ($this->customerNumberProvider)(), ]; try { @@ -121,15 +116,4 @@ public function getCheckout(): Checkout ) ); } - - private function provideCustomerNumber(): string - { - $userId = $this->session->get('sUserId'); - if (!$userId) { - return ''; - } - $customer = $this->modelManager->getRepository(Customer::class)->find($userId); - - return $customer ? (string) $customer->getNumber() : ''; - } } diff --git a/Resources/services/components.xml b/Resources/services/components.xml index 621e0c50..4a6a23d4 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -37,8 +37,7 @@ - - + diff --git a/Resources/services/shopware.xml b/Resources/services/shopware.xml index 490cb309..7f42d842 100644 --- a/Resources/services/shopware.xml +++ b/Resources/services/shopware.xml @@ -7,5 +7,9 @@ + + + + diff --git a/Shopware/Provider/CustomerNumberProvider.php b/Shopware/Provider/CustomerNumberProvider.php new file mode 100644 index 00000000..09be63b0 --- /dev/null +++ b/Shopware/Provider/CustomerNumberProvider.php @@ -0,0 +1,32 @@ +session = $session; + $this->modelManager = $modelManager; + } + + public function __invoke(): string + { + $userId = $this->session->get('sUserId'); + if (!$userId) { + return ''; + } + $customer = $this->modelManager->getRepository(Customer::class)->find($userId); + + return $customer ? (string) $customer->getNumber() : ''; + } +} diff --git a/Shopware/Provider/CustomerNumberProviderInterface.php b/Shopware/Provider/CustomerNumberProviderInterface.php new file mode 100644 index 00000000..3c502f4a --- /dev/null +++ b/Shopware/Provider/CustomerNumberProviderInterface.php @@ -0,0 +1,10 @@ +session = $this->prophesize(Enlight_Components_Session_Namespace::class); + $this->modelManager = $this->prophesize(ModelManager::class); + $this->customerNumberProvider = new CustomerNumberProvider( + $this->session->reveal(), + $this->modelManager->reveal() + ); + } + + /** @test */ + public function it_is_a_customer_number_provider(): void + { + $this->assertInstanceOf(CustomerNumberProviderInterface::class, $this->customerNumberProvider); + } + + /** @test */ + public function it_returns_empty_string_when_no_user_id_in_session(): void + { + $this->session->get('sUserId')->shouldBeCalledOnce()->willReturn(null); + $this->modelManager->getRepository(Customer::class)->shouldNotBeCalled(); + $customerNumber = ($this->customerNumberProvider)(); + + $this->assertEquals('', $customerNumber); + } + + /** @test */ + public function it_returns_empty_string_when_no_customer_returned_from_repository(): void + { + $customerRepository = $this->prophesize(EntityRepository::class); + + $this->session->get('sUserId')->shouldBeCalledOnce()->willReturn($userId = '123'); + $this->modelManager->getRepository(Customer::class) + ->shouldBeCalledOnce() + ->willReturn($customerRepository->reveal()); + $customerRepository->find($userId)->willReturn(null); + + $customerNumber = ($this->customerNumberProvider)(); + $this->assertEquals('', $customerNumber); + } + + /** @test */ + public function it_returns_customer_number(): void + { + $customer = new Customer(); + $customer->setNumber($customerNumber = 'abc'); + + $customerRepository = $this->prophesize(EntityRepository::class); + + $this->session->get('sUserId')->shouldBeCalledOnce()->willReturn($customerNumber); + $this->modelManager->getRepository(Customer::class) + ->shouldBeCalledOnce() + ->willReturn($customerRepository->reveal()); + $customerRepository->find($customerNumber) + ->willReturn($customer); + + $customerNumberExpected = ($this->customerNumberProvider)(); + $this->assertEquals($customerNumberExpected, $customerNumber); + } +} From 1ab0bb2ea888b0e9d84a237fd5592a45fe14ab87 Mon Sep 17 00:00:00 2001 From: davebueds Date: Tue, 15 Feb 2022 15:20:39 +0100 Subject: [PATCH 070/136] ASW-470 add RecurringPaymentToken model and unit test --- AdyenPayment.php | 2 + .../RecurringPaymentToken.php | 165 ++++++++++++++++++ .../RecurringPaymentTokenTest.php | 114 ++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 Models/RecurringPayment/RecurringPaymentToken.php create mode 100644 tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php diff --git a/AdyenPayment.php b/AdyenPayment.php index 44476daa..1a648998 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -10,6 +10,7 @@ use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Notification; use AdyenPayment\Models\PaymentInfo; +use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; use AdyenPayment\Models\Refund; use AdyenPayment\Models\TextNotification; use AdyenPayment\Models\UserPreference; @@ -171,6 +172,7 @@ private function getModelMetaData(): array $entityManager->getClassMetadata(Refund::class), $entityManager->getClassMetadata(TextNotification::class), $entityManager->getClassMetadata(UserPreference::class), + $entityManager->getClassMetadata(RecurringPaymentToken::class), ]; } diff --git a/Models/RecurringPayment/RecurringPaymentToken.php b/Models/RecurringPayment/RecurringPaymentToken.php new file mode 100644 index 00000000..9c7b7c8f --- /dev/null +++ b/Models/RecurringPayment/RecurringPaymentToken.php @@ -0,0 +1,165 @@ +setCreatedAt(new \DateTimeImmutable()); + $this->setUpdatedAt(new \DateTimeImmutable()); + } + + public static function create( + string $customerId, + string $recurringDetailReference, + string $pspReference, + ?string $orderNumber, + PaymentResultCodes $resultCode, + int $amountValue, + string $amountCurrency + ): self { + $new = new self(); + $new->customerId = $customerId; + $new->recurringDetailReference = $recurringDetailReference; + $new->pspReference = $pspReference; + $new->orderNumber = $orderNumber ?? ''; + $new->resultCode = $resultCode->resultCode(); + $new->amountValue = $amountValue; + $new->amountCurrency = $amountCurrency; + + return $new; + } + + public function getId(): int + { + return $this->id; + } + + public function customerId(): string + { + return $this->customerId; + } + + public function recurringDetailReference(): string + { + return $this->recurringDetailReference; + } + + public function pspReference(): string + { + return $this->pspReference; + } + + public function orderNumber(): string + { + return $this->orderNumber; + } + + public function resultCode(): string + { + return $this->resultCode; + } + + public function amountValue(): int + { + return $this->amountValue; + } + + public function amountCurrency(): string + { + return $this->amountCurrency; + } + + public function createdAt(): \DateTimeImmutable + { + return $this->createdAt; + } + + public function setCreatedAt(\DateTimeImmutable $createdAt): void + { + $this->createdAt = $createdAt; + } + + public function updatedAt(): \DateTimeImmutable + { + return $this->updatedAt; + } + + public function setUpdatedAt(\DateTimeImmutable $updatedAt): void + { + $this->updatedAt = $updatedAt; + } + + public function isSubscription(): bool + { + return '' === $this->orderNumber(); + } + + public function isOneOffPayment(): bool + { + return '' !== $this->orderNumber(); + } +} diff --git a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php new file mode 100644 index 00000000..092d55a7 --- /dev/null +++ b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php @@ -0,0 +1,114 @@ +recurringPaymentToken = RecurringPaymentToken::create( + $customerId = 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', + $recurringDetailReference = '8415698462516992', + $pspReference = '8515815919501547', + $orderNumber = 'YOUR_ORDER_NUMBER', + $resultCode = PaymentResultCodes::authorised(), + $amountValue = 10500, + $amountCurrency = 'EUR' + ); + } + + /** @test */ + public function it_contains_a_customer_id(): void + { + $this->assertEquals('YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', $this->recurringPaymentToken->customerId()); + } + + /** @test */ + public function it_contains_a_recurring_detail_reference(): void + { + $this->assertEquals('8415698462516992', $this->recurringPaymentToken->recurringDetailReference()); + } + + /** @test */ + public function it_contains_a_psp_reference(): void + { + $this->assertEquals('8515815919501547', $this->recurringPaymentToken->pspReference()); + } + + /** @test */ + public function it_contains_an_order_number(): void + { + $this->assertEquals('YOUR_ORDER_NUMBER', $this->recurringPaymentToken->orderNumber()); + } + + /** @test */ + public function it_contains_a_result_code(): void + { + $this->assertEquals('Authorised', $this->recurringPaymentToken->resultCode()); + } + + /** @test */ + public function it_contains_an_amount_value(): void + { + $this->assertIsInt($this->recurringPaymentToken->amountValue()); + $this->assertEquals(10500, $this->recurringPaymentToken->amountValue()); + } + + /** @test */ + public function it_contains_an_amount_currency(): void + { + $this->assertEquals('EUR', $this->recurringPaymentToken->amountCurrency()); + } + + /** @test */ + public function it_contains_a_created_at_timestamp(): void + { + $this->assertInstanceOf(\DateTimeImmutable::class, $this->recurringPaymentToken->createdAt()); + } + + /** @test */ + public function it_contains_an_updated_at_timestamp(): void + { + $this->assertInstanceOf(\DateTimeImmutable::class, $this->recurringPaymentToken->updatedAt()); + } + + /** @test */ + public function it_knows_when_it_is_a_one_off_payment(): void + { + $this->assertTrue($this->recurringPaymentToken->isOneOffPayment()); + } + + /** @test */ + public function it_knows_when_it_is_a_subscription(): void + { + $recurringPaymentTokenOrderNumberNull = RecurringPaymentToken::create( + 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', + '8415698462516992', + '8515815919501547', + $orderNumber = null, + PaymentResultCodes::authorised(), + 10500, + 'EUR' + ); + $this->assertTrue($recurringPaymentTokenOrderNumberNull->isSubscription()); + + $recurringPaymentTokenOrderNumberEmpty = RecurringPaymentToken::create( + 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', + '8415698462516992', + '8515815919501547', + $orderNumber = '', + PaymentResultCodes::authorised(), + 10500, + 'EUR' + ); + $this->assertTrue($recurringPaymentTokenOrderNumberEmpty->isSubscription()); + } +} From 45523d62720cd510448de264d4fd75e8d37d64d7 Mon Sep 17 00:00:00 2001 From: davebueds Date: Wed, 16 Feb 2022 16:18:56 +0100 Subject: [PATCH 071/136] ASW-472 Add shopperinteractions, fix tests --- .../RecurringPayment/ShopperInteraction.php | 30 +++++++++------- .../ShopperInteractionTest.php | 36 ++++++++++++++----- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/Models/RecurringPayment/ShopperInteraction.php b/Models/RecurringPayment/ShopperInteraction.php index beffae1d..bf219000 100644 --- a/Models/RecurringPayment/ShopperInteraction.php +++ b/Models/RecurringPayment/ShopperInteraction.php @@ -8,7 +8,9 @@ final class ShopperInteraction { private const CONTAUTH = 'ContAuth'; private const ECOMMERCE = 'Ecommerce'; - private string $value; + private const MOTO = 'Moto'; + private const POS = 'POS'; + private string $shopperInteraction; private function __construct(string $shopperInteraction) { @@ -16,17 +18,17 @@ private function __construct(string $shopperInteraction) throw new \InvalidArgumentException('Invalid shopper interaction: "'.$shopperInteraction.'"'); } - $this->value = $shopperInteraction; + $this->shopperInteraction = $shopperInteraction; } - public function value(): string + public function shopperInteraction(): string { - return $this->value; + return $this->shopperInteraction; } public function equals(ShopperInteraction $paymentShopperInteraction): bool { - return $paymentShopperInteraction->value() === $this->value; + return $paymentShopperInteraction->shopperInteraction() === $this->shopperInteraction; } public static function load(string $shopperInteraction): self @@ -34,14 +36,6 @@ public static function load(string $shopperInteraction): self return new self($shopperInteraction); } - private function availableShopperInteractions(): array - { - return [ - self::CONTAUTH, - self::ECOMMERCE, - ]; - } - public static function contAuth(): self { return new self(self::CONTAUTH); @@ -51,4 +45,14 @@ public static function ecommerce(): self { return new self(self::ECOMMERCE); } + + private function availableShopperInteractions(): array + { + return [ + self::CONTAUTH, + self::ECOMMERCE, + self::MOTO, + self::POS, + ]; + } } diff --git a/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php b/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php index 662d24be..d71126f5 100644 --- a/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php +++ b/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php @@ -9,19 +9,41 @@ class ShopperInteractionTest extends TestCase { + private ShopperInteraction $shopperInteraction; + + protected function setUp(): void + { + $this->shopperInteraction = ShopperInteraction::contAuth(); + } + + /** @test */ + public function it_contains_a_shopper_interaction(): void + { + $this->assertInstanceOf(ShopperInteraction::class, $this->shopperInteraction); + } + + /** @test */ + public function it_can_compare_shopper_interaction_objects(): void + { + $this->assertTrue($this->shopperInteraction->equals(ShopperInteraction::contAuth())); + $this->assertFalse($this->shopperInteraction->equals(ShopperInteraction::ecommerce())); + } + /** @test */ - public function it_can_construct_through_named_constructor(): void + public function it_checks_shopper_interaction_on_immutabillity(): void { - $this->assertInstanceOf(ShopperInteraction::class, ShopperInteraction::contAuth()); + $shopperInteractionContAuth = ShopperInteraction::contAuth(); + $this->assertEquals($this->shopperInteraction, $shopperInteractionContAuth); + $this->assertNotSame($this->shopperInteraction, $shopperInteractionContAuth); } /** * @dataProvider shopperInteractionProvider * @test */ - public function it_contains_shopper_interaction(ShopperInteraction $shopperInteraction, string $expected): void + public function it_can_be_constructed_with_named_constructors(ShopperInteraction $shopperInteraction, string $expected): void { - $this->assertEquals($expected, $shopperInteraction->value()); + $this->assertEquals($expected, $shopperInteraction->shopperInteraction()); } public function shopperInteractionProvider(): \Generator @@ -54,9 +76,7 @@ public function it_can_check_it_is_not_equal_to_another_value_object(): void /** @test */ public function it_can_load_a_shopper_interaction(): void { - $this->assertEquals( - ShopperInteraction::ecommerce(), - ShopperInteraction::load('Ecommerce') - ); + $result = ShopperInteraction::ecommerce(); + $this->assertEquals(ShopperInteraction::ecommerce(), $result); } } From 8bf8bf90cd5e375d5e0925f64ba0d82cea4af0e1 Mon Sep 17 00:00:00 2001 From: davebueds Date: Wed, 16 Feb 2022 16:31:30 +0100 Subject: [PATCH 072/136] ASW-473 fix cr feedback --- .../RecurringProcessingModel.php | 28 +++++++------ .../RecurringProcessingModelTest.php | 40 ++++++++++++------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/Models/RecurringPayment/RecurringProcessingModel.php b/Models/RecurringPayment/RecurringProcessingModel.php index 927a920b..9df5ac03 100644 --- a/Models/RecurringPayment/RecurringProcessingModel.php +++ b/Models/RecurringPayment/RecurringProcessingModel.php @@ -8,7 +8,8 @@ final class RecurringProcessingModel { private const CARDONFILE = 'CardOnFile'; private const SUBSCRIPTION = 'Subscription'; - private string $value; + private const UNSCHEDULED_CARD_ON_FILE = 'UnscheduledCardOnFile'; + private string $recurringProcessingModel; private function __construct(string $recurringProcessingModel) { @@ -16,17 +17,17 @@ private function __construct(string $recurringProcessingModel) throw new \InvalidArgumentException('Invalid recurring processing model: "'.$recurringProcessingModel.'"'); } - $this->value = $recurringProcessingModel; + $this->recurringProcessingModel = $recurringProcessingModel; } - public function value(): string + public function recurringProcessingModel(): string { - return $this->value; + return $this->recurringProcessingModel; } public function equals(RecurringProcessingModel $recurringProcessingModel): bool { - return $recurringProcessingModel->value() === $this->value; + return $recurringProcessingModel->recurringProcessingModel() === $this->recurringProcessingModel; } public static function load(string $recurringProcessingModel): self @@ -34,14 +35,6 @@ public static function load(string $recurringProcessingModel): self return new self($recurringProcessingModel); } - private function availableRecurringProcessingModels(): array - { - return [ - self::CARDONFILE, - self::SUBSCRIPTION, - ]; - } - public static function cardOnFile(): self { return new self(self::CARDONFILE); @@ -51,4 +44,13 @@ public static function subscription(): self { return new self(self::SUBSCRIPTION); } + + private function availableRecurringProcessingModels(): array + { + return [ + self::CARDONFILE, + self::SUBSCRIPTION, + self::UNSCHEDULED_CARD_ON_FILE, + ]; + } } diff --git a/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php b/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php index 7085b847..b49bf970 100644 --- a/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php +++ b/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php @@ -9,10 +9,32 @@ class RecurringProcessingModelTest extends TestCase { + private RecurringProcessingModel $recurringProcessingModel; + + protected function setUp(): void + { + $this->recurringProcessingModel = RecurringProcessingModel::cardOnFile(); + } + + /** @test */ + public function it_contains_a_recurring_processing_model(): void + { + $this->assertInstanceOf(RecurringProcessingModel::class, $this->recurringProcessingModel); + } + + /** @test */ + public function it_can_compare_recurring_processing_model_objects(): void + { + $this->assertTrue($this->recurringProcessingModel->equals(RecurringProcessingModel::cardOnFile())); + $this->assertFalse($this->recurringProcessingModel->equals(RecurringProcessingModel::subscription())); + } + /** @test */ - public function it_can_construct_through_named_constructor(): void + public function it_checks_recurring_processing_model_on_immutabillity(): void { - $this->assertInstanceOf(RecurringProcessingModel::class, RecurringProcessingModel::cardOnFile()); + $recurringProcessingModel = RecurringProcessingModel::cardOnFile(); + $this->assertEquals($this->recurringProcessingModel, $recurringProcessingModel); + $this->assertNotSame($this->recurringProcessingModel, $recurringProcessingModel); } /** @@ -22,7 +44,7 @@ public function it_can_construct_through_named_constructor(): void public function it_contains_recurring_processing_model( RecurringProcessingModel $recurringProcessingModel, string $expected ): void { - $this->assertEquals($expected, $recurringProcessingModel->value()); + $this->assertEquals($expected, $recurringProcessingModel->recurringProcessingModel()); } public function recurringProcessingModelProvider(): \Generator @@ -40,18 +62,6 @@ public function it_throws_an_invalid_argument_exception_when_recurring_processin RecurringProcessingModel::load('test'); } - /** @test */ - public function it_can_check_it_is_equal_to_another_value_object(): void - { - $this->assertTrue(RecurringProcessingModel::cardOnFile()->equals(RecurringProcessingModel::cardOnFile())); - } - - /** @test */ - public function it_can_check_it_is_not_equal_to_another_value_object(): void - { - $this->assertFalse(RecurringProcessingModel::cardOnFile()->equals(RecurringProcessingModel::subscription())); - } - /** @test */ public function it_can_load_a_recurring_processing_model(): void { From c48f359707d5c8d4311c43fdf59c490898f624fa Mon Sep 17 00:00:00 2001 From: davebueds Date: Wed, 16 Feb 2022 16:31:30 +0100 Subject: [PATCH 073/136] ASW-473 fix cr feedback --- .../RecurringPayment/ShopperInteractionTest.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php b/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php index d71126f5..37e307d6 100644 --- a/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php +++ b/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php @@ -61,18 +61,6 @@ public function it_throws_an_invalid_argument_exception_when_shopper_interaction ShopperInteraction::load('test'); } - /** @test */ - public function it_can_check_it_is_equal_to_another_value_object(): void - { - $this->assertTrue(ShopperInteraction::ecommerce()->equals(ShopperInteraction::ecommerce())); - } - - /** @test */ - public function it_can_check_it_is_not_equal_to_another_value_object(): void - { - $this->assertFalse(ShopperInteraction::ecommerce()->equals(ShopperInteraction::contAuth())); - } - /** @test */ public function it_can_load_a_shopper_interaction(): void { From e6cc4aa1e15301300ffeecbb109b44ae52339310 Mon Sep 17 00:00:00 2001 From: davebueds Date: Wed, 16 Feb 2022 17:01:16 +0100 Subject: [PATCH 074/136] ASW-477 apply fixes CR --- Components/Adyen/PaymentMethodService.php | 2 +- Resources/services/components.xml | 2 +- Resources/services/session.xml | 4 ++++ Resources/services/shopware.xml | 4 ---- .../Provider => Session}/CustomerNumberProvider.php | 2 +- .../CustomerNumberProviderInterface.php | 2 +- .../CustomerNumberProviderTest.php | 12 ++++++------ 7 files changed, 14 insertions(+), 14 deletions(-) rename {Shopware/Provider => Session}/CustomerNumberProvider.php (95%) rename {Shopware/Provider => Session}/CustomerNumberProviderInterface.php (74%) rename tests/Unit/{Shopware/Provider => Session}/CustomerNumberProviderTest.php (87%) diff --git a/Components/Adyen/PaymentMethodService.php b/Components/Adyen/PaymentMethodService.php index c2f97b1c..0c041973 100644 --- a/Components/Adyen/PaymentMethodService.php +++ b/Components/Adyen/PaymentMethodService.php @@ -10,7 +10,7 @@ use AdyenPayment\Collection\Payment\PaymentMethodCollection; use AdyenPayment\Components\Configuration; use AdyenPayment\Models\Enum\Channel; -use AdyenPayment\Shopware\Provider\CustomerNumberProviderInterface; +use AdyenPayment\Session\CustomerNumberProviderInterface; use Psr\Log\LoggerInterface; final class PaymentMethodService implements PaymentMethodServiceInterface diff --git a/Resources/services/components.xml b/Resources/services/components.xml index 4a6a23d4..cc0b6e57 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -37,7 +37,7 @@ - + diff --git a/Resources/services/session.xml b/Resources/services/session.xml index 46893c43..cc51709a 100644 --- a/Resources/services/session.xml +++ b/Resources/services/session.xml @@ -5,5 +5,9 @@ + + + + diff --git a/Resources/services/shopware.xml b/Resources/services/shopware.xml index 7f42d842..490cb309 100644 --- a/Resources/services/shopware.xml +++ b/Resources/services/shopware.xml @@ -7,9 +7,5 @@ - - - - diff --git a/Shopware/Provider/CustomerNumberProvider.php b/Session/CustomerNumberProvider.php similarity index 95% rename from Shopware/Provider/CustomerNumberProvider.php rename to Session/CustomerNumberProvider.php index 09be63b0..d93abf1a 100644 --- a/Shopware/Provider/CustomerNumberProvider.php +++ b/Session/CustomerNumberProvider.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AdyenPayment\Shopware\Provider; +namespace AdyenPayment\Session; use Enlight_Components_Session_Namespace; use Shopware\Components\Model\ModelManager; diff --git a/Shopware/Provider/CustomerNumberProviderInterface.php b/Session/CustomerNumberProviderInterface.php similarity index 74% rename from Shopware/Provider/CustomerNumberProviderInterface.php rename to Session/CustomerNumberProviderInterface.php index 3c502f4a..d47396a6 100644 --- a/Shopware/Provider/CustomerNumberProviderInterface.php +++ b/Session/CustomerNumberProviderInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AdyenPayment\Shopware\Provider; +namespace AdyenPayment\Session; interface CustomerNumberProviderInterface { diff --git a/tests/Unit/Shopware/Provider/CustomerNumberProviderTest.php b/tests/Unit/Session/CustomerNumberProviderTest.php similarity index 87% rename from tests/Unit/Shopware/Provider/CustomerNumberProviderTest.php rename to tests/Unit/Session/CustomerNumberProviderTest.php index 636563e0..d47fcb15 100644 --- a/tests/Unit/Shopware/Provider/CustomerNumberProviderTest.php +++ b/tests/Unit/Session/CustomerNumberProviderTest.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Unit\Shopware\Provider; +namespace Unit\Session; -use AdyenPayment\Shopware\Provider\CustomerNumberProvider; -use AdyenPayment\Shopware\Provider\CustomerNumberProviderInterface; +use AdyenPayment\Session\CustomerNumberProvider; +use AdyenPayment\Session\CustomerNumberProviderInterface; use Doctrine\ORM\EntityRepository; use Enlight_Components_Session_Namespace; use PHPUnit\Framework\TestCase; @@ -42,7 +42,7 @@ public function it_is_a_customer_number_provider(): void } /** @test */ - public function it_returns_empty_string_when_no_user_id_in_session(): void + public function it_provides_empty_string_when_no_user_id_in_session(): void { $this->session->get('sUserId')->shouldBeCalledOnce()->willReturn(null); $this->modelManager->getRepository(Customer::class)->shouldNotBeCalled(); @@ -52,7 +52,7 @@ public function it_returns_empty_string_when_no_user_id_in_session(): void } /** @test */ - public function it_returns_empty_string_when_no_customer_returned_from_repository(): void + public function it_provides_empty_string_when_no_customer_returned_from_repository(): void { $customerRepository = $this->prophesize(EntityRepository::class); @@ -67,7 +67,7 @@ public function it_returns_empty_string_when_no_customer_returned_from_repositor } /** @test */ - public function it_returns_customer_number(): void + public function it_provides_customer_number(): void { $customer = new Customer(); $customer->setNumber($customerNumber = 'abc'); From 8dc030e91a4e96dc19440cd698cee318c0e50ea5 Mon Sep 17 00:00:00 2001 From: davebueds Date: Wed, 16 Feb 2022 19:01:36 +0100 Subject: [PATCH 075/136] ASW-470 make orderNumber not nullable, add tests, add indexes --- .../RecurringPaymentToken.php | 16 ++++++---- .../RecurringPaymentTokenTest.php | 30 +++++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/Models/RecurringPayment/RecurringPaymentToken.php b/Models/RecurringPayment/RecurringPaymentToken.php index 9c7b7c8f..45883a93 100644 --- a/Models/RecurringPayment/RecurringPaymentToken.php +++ b/Models/RecurringPayment/RecurringPaymentToken.php @@ -10,7 +10,11 @@ /** * @ORM\Entity - * @ORM\Table(name="s_plugin_adyen_payment_recurring_payment_token") + * @ORM\Table(name="s_plugin_adyen_payment_recurring_payment_token", indexes={ + * @ORM\Index(name="idx_customer_id", columns={"customer_id"}), + * @ORM\Index(name="idx_psp_reference", columns={"psp_reference"}), + * @ORM\Index(name="idx_order_number", columns={"order_number"}) + * }) */ class RecurringPaymentToken extends ModelEntity { @@ -22,7 +26,7 @@ class RecurringPaymentToken extends ModelEntity private int $id; /** - * @ORM\Column(name="customer_id", type="text", nullable=false) + * @ORM\Column(name="customer_id", type="string", length=255, nullable=false) */ private string $customerId; @@ -32,12 +36,12 @@ class RecurringPaymentToken extends ModelEntity private string $recurringDetailReference; /** - * @ORM\Column(name="psp_reference", type="text", nullable=false) + * @ORM\Column(name="psp_reference", type="string", length=255, nullable=false) */ private string $pspReference; /** - * @ORM\Column(name="order_number", type="text", nullable=false) + * @ORM\Column(name="order_number", type="string", length=255, nullable=false) */ private string $orderNumber = ''; @@ -76,7 +80,7 @@ public static function create( string $customerId, string $recurringDetailReference, string $pspReference, - ?string $orderNumber, + string $orderNumber, PaymentResultCodes $resultCode, int $amountValue, string $amountCurrency @@ -85,7 +89,7 @@ public static function create( $new->customerId = $customerId; $new->recurringDetailReference = $recurringDetailReference; $new->pspReference = $pspReference; - $new->orderNumber = $orderNumber ?? ''; + $new->orderNumber = $orderNumber; $new->resultCode = $resultCode->resultCode(); $new->amountValue = $amountValue; $new->amountCurrency = $amountCurrency; diff --git a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php index 092d55a7..cdb1d8a4 100644 --- a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php +++ b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php @@ -7,6 +7,7 @@ use AdyenPayment\Models\PaymentResultCodes; use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; use PHPUnit\Framework\TestCase; +use Shopware\Components\Model\ModelEntity; class RecurringPaymentTokenTest extends TestCase { @@ -25,6 +26,12 @@ protected function setUp(): void ); } + /** @test */ + public function it_is_a_model_entity(): void + { + $this->assertInstanceOf(ModelEntity::class, $this->recurringPaymentToken); + } + /** @test */ public function it_contains_a_customer_id(): void { @@ -58,7 +65,6 @@ public function it_contains_a_result_code(): void /** @test */ public function it_contains_an_amount_value(): void { - $this->assertIsInt($this->recurringPaymentToken->amountValue()); $this->assertEquals(10500, $this->recurringPaymentToken->amountValue()); } @@ -71,13 +77,24 @@ public function it_contains_an_amount_currency(): void /** @test */ public function it_contains_a_created_at_timestamp(): void { + $createdAt = new \DateTimeImmutable(); + $this->recurringPaymentToken->setCreatedAt($createdAt); $this->assertInstanceOf(\DateTimeImmutable::class, $this->recurringPaymentToken->createdAt()); + $this->assertStringContainsString( + $createdAt->format('d/m/y'), + $this->recurringPaymentToken->createdAt()->format('d/m/y') + ); } /** @test */ public function it_contains_an_updated_at_timestamp(): void { + $updatedAt = new \DateTimeImmutable(); $this->assertInstanceOf(\DateTimeImmutable::class, $this->recurringPaymentToken->updatedAt()); + $this->assertStringContainsString( + $updatedAt->format('d/m/y'), + $this->recurringPaymentToken->updatedAt()->format('d/m/y') + ); } /** @test */ @@ -89,17 +106,6 @@ public function it_knows_when_it_is_a_one_off_payment(): void /** @test */ public function it_knows_when_it_is_a_subscription(): void { - $recurringPaymentTokenOrderNumberNull = RecurringPaymentToken::create( - 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', - '8415698462516992', - '8515815919501547', - $orderNumber = null, - PaymentResultCodes::authorised(), - 10500, - 'EUR' - ); - $this->assertTrue($recurringPaymentTokenOrderNumberNull->isSubscription()); - $recurringPaymentTokenOrderNumberEmpty = RecurringPaymentToken::create( 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', '8415698462516992', From 1e2ff6998029ee7e7dacc735fa4ae91018a27147 Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 17 Feb 2022 08:20:37 +0100 Subject: [PATCH 076/136] ASW-476 add invalid status + test --- Models/PaymentResultCodes.php | 7 +++++++ tests/Unit/Models/PaymentResultCodesTest.php | 1 + 2 files changed, 8 insertions(+) diff --git a/Models/PaymentResultCodes.php b/Models/PaymentResultCodes.php index f6a5fec0..daa7eb32 100644 --- a/Models/PaymentResultCodes.php +++ b/Models/PaymentResultCodes.php @@ -11,6 +11,7 @@ final class PaymentResultCodes private const CHALLENGESHOPPER = 'ChallengeShopper'; private const ERROR = 'Error'; private const IDENTIFYSHOPPER = 'IdentifyShopper'; + private const INVALID = 'Invalid'; private const PENDING = 'Pending'; private const RECEIVED = 'Received'; private const REDIRECTSHOPPER = 'RedirectShopper'; @@ -51,6 +52,7 @@ private function availableResultCodes(): array self::CANCELLED, self::CHALLENGESHOPPER, self::ERROR, + self::INVALID, self::IDENTIFYSHOPPER, self::PENDING, self::RECEIVED, @@ -79,6 +81,11 @@ public static function error(): self return new self(self::ERROR); } + public static function invalid(): self + { + return new self(self::INVALID); + } + public static function identifyShopper(): self { return new self(self::IDENTIFYSHOPPER); diff --git a/tests/Unit/Models/PaymentResultCodesTest.php b/tests/Unit/Models/PaymentResultCodesTest.php index 55f6f35a..cc8b3c5e 100644 --- a/tests/Unit/Models/PaymentResultCodesTest.php +++ b/tests/Unit/Models/PaymentResultCodesTest.php @@ -30,6 +30,7 @@ public function resultCodeProvider(): \Generator yield [PaymentResultCodes::cancelled(), 'Cancelled']; yield [PaymentResultCodes::challengeShopper(), 'ChallengeShopper']; yield [PaymentResultCodes::error(), 'Error']; + yield [PaymentResultCodes::invalid(), 'Invalid']; yield [PaymentResultCodes::identifyShopper(), 'IdentifyShopper']; yield [PaymentResultCodes::pending(), 'Pending']; yield [PaymentResultCodes::received(), 'Received']; From da26bc6ef29605172d1f4ec27bf12210891a3404 Mon Sep 17 00:00:00 2001 From: davebueds Date: Tue, 15 Feb 2022 17:46:01 +0100 Subject: [PATCH 077/136] ASW-469 Add mapper RecurringTokenMapper and unit test --- Recurring/Mapper/RecurringTokenMapper.php | 26 +++ .../Mapper/RecurringTokenMapperInterface.php | 12 ++ .../Mapper/RecurringTokenMapperTest.php | 152 ++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 Recurring/Mapper/RecurringTokenMapper.php create mode 100644 Recurring/Mapper/RecurringTokenMapperInterface.php create mode 100644 tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php diff --git a/Recurring/Mapper/RecurringTokenMapper.php b/Recurring/Mapper/RecurringTokenMapper.php new file mode 100644 index 00000000..eb9d2524 --- /dev/null +++ b/Recurring/Mapper/RecurringTokenMapper.php @@ -0,0 +1,26 @@ +adyenPaymentsResponseJson = '{ + "additionalData": { + "recurring.recurringDetailReference": "8415698462516992", + "recurring.shopperReference": "YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j" + }, + "pspReference": "8515815919501547", + "resultCode": "Authorised", + "amount": { + "currency": "USD", + "value": 0 + }, + "merchantReference": "YOUR_ORDER_NUMBER" + }'; + + $this->recurringTokenMapper = new RecurringTokenMapper(); + } + + /** @test */ + public function it_is_a_recurring_token_mapper(): void + { + $this->assertInstanceOf(RecurringTokenMapperInterface::class, $this->recurringTokenMapper); + } + + /** @test */ + public function it_can_map_from_array(): void + { + $recurringPaymentToken = ($this->recurringTokenMapper)(json_decode($this->adyenPaymentsResponseJson, true)); + + $this->assertEquals('YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', $recurringPaymentToken->customerId()); + $this->assertEquals('8415698462516992', $recurringPaymentToken->recurringDetailReference()); + $this->assertEquals('8515815919501547', $recurringPaymentToken->pspReference()); + $this->assertEquals('YOUR_ORDER_NUMBER', $recurringPaymentToken->orderNumber()); + $this->assertEquals('Authorised', $recurringPaymentToken->resultCode()); + $this->assertIsInt($recurringPaymentToken->amountValue()); + $this->assertEquals(0, $recurringPaymentToken->amountValue()); + $this->assertEquals('USD', $recurringPaymentToken->amountCurrency()); + } + + /** @test */ + public function it_maps_empty_string_when_customer_id_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['additionalData']['recurring.shopperReference']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals('', $recurringPaymentToken->customerId()); + } + + /** @test */ + public function it_maps_empty_string_when_recurring_detail_reference_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['additionalData']['recurring.recurringDetailReference']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals('', $recurringPaymentToken->recurringDetailReference()); + } + + /** @test */ + public function it_maps_empty_string_when_additional_data_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['additionalData']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals('', $recurringPaymentToken->customerId()); + $this->assertEquals('', $recurringPaymentToken->recurringDetailReference()); + } + + /** @test */ + public function it_maps_empty_string_when_psp_reference_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['pspReference']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals('', $recurringPaymentToken->pspReference()); + } + + /** @test */ + public function it_maps_empty_string_when_merchant_reference_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['merchantReference']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals('', $recurringPaymentToken->orderNumber()); + } + + /** @test */ + public function it_maps_refused_result_code_when_result_code_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['resultCode']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals('Refused', $recurringPaymentToken->resultCode()); + } + + /** @test */ + public function it_maps_to_zero_when_amount_value_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['amount']['value']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals(0, $recurringPaymentToken->amountValue()); + } + + /** @test */ + public function it_maps_to_empty_string_when_amount_currency_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['amount']['currency']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals('', $recurringPaymentToken->amountCurrency()); + } + + /** @test */ + public function it_maps_to_empty_string_and_zero_when_amount_not_in_response(): void + { + $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); + unset($adyenResponse['amount']); + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + + $this->assertEquals(0, $recurringPaymentToken->amountValue()); + $this->assertEquals('', $recurringPaymentToken->amountCurrency()); + } +} From 87d07c50dd9be089d7279eef00c0e7a2ba5055fb Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 17 Feb 2022 08:10:29 +0100 Subject: [PATCH 078/136] ASW-469 add invalidPaymentsResponseException + test --- Exceptions/InvalidPaymentsResponseException.php | 13 +++++++++++++ Recurring/Mapper/RecurringTokenMapper.php | 5 +++++ .../Recurring/Mapper/RecurringTokenMapperTest.php | 10 ++++++++++ 3 files changed, 28 insertions(+) create mode 100644 Exceptions/InvalidPaymentsResponseException.php diff --git a/Exceptions/InvalidPaymentsResponseException.php b/Exceptions/InvalidPaymentsResponseException.php new file mode 100644 index 00000000..7ffd3c1f --- /dev/null +++ b/Exceptions/InvalidPaymentsResponseException.php @@ -0,0 +1,13 @@ +assertInstanceOf(RecurringTokenMapperInterface::class, $this->recurringTokenMapper); } + /** @test */ + public function it_throws_invalid_payments_response_exception(): void + { + $this->expectException(InvalidPaymentsResponseException::class); + $this->expectExceptionMessage('Payments response not found.'); + + ($this->recurringTokenMapper)([]); + } + /** @test */ public function it_can_map_from_array(): void { From 2f79eb2937d179519e40d619eed526ec4f4e6ecd Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 17 Feb 2022 09:52:12 +0100 Subject: [PATCH 079/136] ASW-469 refactor test --- Recurring/Mapper/RecurringTokenMapper.php | 4 +- .../Mapper/RecurringTokenMapperTest.php | 132 +++++++----------- 2 files changed, 49 insertions(+), 87 deletions(-) diff --git a/Recurring/Mapper/RecurringTokenMapper.php b/Recurring/Mapper/RecurringTokenMapper.php index 7bc50c83..8ac9defe 100644 --- a/Recurring/Mapper/RecurringTokenMapper.php +++ b/Recurring/Mapper/RecurringTokenMapper.php @@ -21,9 +21,9 @@ public function __invoke(array $rawData): RecurringPaymentToken $rawData['additionalData']['recurring.recurringDetailReference'] ?? '', $rawData['pspReference'] ?? '', $rawData['merchantReference'] ?? '', - isset($rawData['resultCode']) ? + array_key_exists('resultCode', $rawData) ? PaymentResultCodes::load($rawData['resultCode']) : - PaymentResultCodes::refused(), + PaymentResultCodes::invalid(), $rawData['amount']['value'] ?? 0, $rawData['amount']['currency'] ?? '' ); diff --git a/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php b/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php index dfa1c121..1378619d 100644 --- a/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php +++ b/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php @@ -14,27 +14,12 @@ class RecurringTokenMapperTest extends TestCase { use ProphecyTrait; - private string $adyenPaymentsResponseJson; /** @var ObjectProphecy|RecurringTokenMapperInterface */ private $recurringTokenMapper; protected function setUp(): void { - $this->adyenPaymentsResponseJson = '{ - "additionalData": { - "recurring.recurringDetailReference": "8415698462516992", - "recurring.shopperReference": "YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j" - }, - "pspReference": "8515815919501547", - "resultCode": "Authorised", - "amount": { - "currency": "USD", - "value": 0 - }, - "merchantReference": "YOUR_ORDER_NUMBER" - }'; - $this->recurringTokenMapper = new RecurringTokenMapper(); } @@ -56,7 +41,20 @@ public function it_throws_invalid_payments_response_exception(): void /** @test */ public function it_can_map_from_array(): void { - $recurringPaymentToken = ($this->recurringTokenMapper)(json_decode($this->adyenPaymentsResponseJson, true)); + $adyenPaymentsResponseArray = [ + 'additionalData' => [ + 'recurring.recurringDetailReference' => '8415698462516992', + 'recurring.shopperReference' => 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', + ], + 'pspReference' => '8515815919501547', + 'resultCode' => 'Authorised', + 'amount' => [ + 'currency' => 'USD', + 'value' => 0, + ], + 'merchantReference' => 'YOUR_ORDER_NUMBER', + ]; + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenPaymentsResponseArray); $this->assertEquals('YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', $recurringPaymentToken->customerId()); $this->assertEquals('8415698462516992', $recurringPaymentToken->recurringDetailReference()); @@ -69,92 +67,56 @@ public function it_can_map_from_array(): void } /** @test */ - public function it_maps_empty_string_when_customer_id_not_in_response(): void - { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['additionalData']['recurring.shopperReference']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); - - $this->assertEquals('', $recurringPaymentToken->customerId()); - } - - /** @test */ - public function it_maps_empty_string_when_recurring_detail_reference_not_in_response(): void - { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['additionalData']['recurring.recurringDetailReference']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); - - $this->assertEquals('', $recurringPaymentToken->recurringDetailReference()); - } - - /** @test */ - public function it_maps_empty_string_when_additional_data_not_in_response(): void + public function it_can_map_default_values(): void { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['additionalData']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + $adyenPaymentsResponseArray = [ + 'additionalData' => [ + ], + 'amount' => [ + ], + ]; + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenPaymentsResponseArray); $this->assertEquals('', $recurringPaymentToken->customerId()); $this->assertEquals('', $recurringPaymentToken->recurringDetailReference()); - } - - /** @test */ - public function it_maps_empty_string_when_psp_reference_not_in_response(): void - { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['pspReference']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); - $this->assertEquals('', $recurringPaymentToken->pspReference()); - } - - /** @test */ - public function it_maps_empty_string_when_merchant_reference_not_in_response(): void - { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['merchantReference']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); - $this->assertEquals('', $recurringPaymentToken->orderNumber()); - } - - /** @test */ - public function it_maps_refused_result_code_when_result_code_not_in_response(): void - { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['resultCode']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); - - $this->assertEquals('Refused', $recurringPaymentToken->resultCode()); - } - - /** @test */ - public function it_maps_to_zero_when_amount_value_not_in_response(): void - { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['amount']['value']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); - + $this->assertEquals('Invalid', $recurringPaymentToken->resultCode()); $this->assertEquals(0, $recurringPaymentToken->amountValue()); + $this->assertEquals('', $recurringPaymentToken->amountCurrency()); } /** @test */ - public function it_maps_to_empty_string_when_amount_currency_not_in_response(): void + public function it_maps_empty_string_when_additional_data_not_in_response(): void { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['amount']['currency']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + $adyenPaymentsResponseArray = [ + 'pspReference' => '8515815919501547', + 'resultCode' => 'Authorised', + 'amount' => [ + 'currency' => 'USD', + 'value' => 0, + ], + 'merchantReference' => 'YOUR_ORDER_NUMBER', + ]; + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenPaymentsResponseArray); - $this->assertEquals('', $recurringPaymentToken->amountCurrency()); + $this->assertEquals('', $recurringPaymentToken->customerId()); + $this->assertEquals('', $recurringPaymentToken->recurringDetailReference()); } /** @test */ public function it_maps_to_empty_string_and_zero_when_amount_not_in_response(): void { - $adyenResponse = json_decode($this->adyenPaymentsResponseJson, true); - unset($adyenResponse['amount']); - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenResponse); + $adyenPaymentsResponseArray = [ + 'additionalData' => [ + 'recurring.recurringDetailReference' => '8415698462516992', + 'recurring.shopperReference' => 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', + ], + 'pspReference' => '8515815919501547', + 'resultCode' => 'Authorised', + 'merchantReference' => 'YOUR_ORDER_NUMBER', + ]; + $recurringPaymentToken = ($this->recurringTokenMapper)($adyenPaymentsResponseArray); $this->assertEquals(0, $recurringPaymentToken->amountValue()); $this->assertEquals('', $recurringPaymentToken->amountCurrency()); From d1f95be6d3bc90981d1cbeefe80be6344f624d17 Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 17 Feb 2022 11:03:40 +0100 Subject: [PATCH 080/136] ASW-476 remove PaymentResultCodeHandler and test, leave it in Adyen.php --- Components/Adyen/PaymentResultCodeHandler.php | 34 -------- .../PaymentResultCodeHandlerInterface.php | 10 --- Controllers/Frontend/Adyen.php | 44 +++++++++- Controllers/Frontend/Process.php | 3 +- Models/PaymentResultCodes.php | 38 ++++----- Resources/services/components.xml | 3 - .../Adyen/PaymentResultCodeHandlerTest.php | 84 ------------------- 7 files changed, 61 insertions(+), 155 deletions(-) delete mode 100644 Components/Adyen/PaymentResultCodeHandler.php delete mode 100644 Components/Adyen/PaymentResultCodeHandlerInterface.php delete mode 100644 tests/Unit/Components/Adyen/PaymentResultCodeHandlerTest.php diff --git a/Components/Adyen/PaymentResultCodeHandler.php b/Components/Adyen/PaymentResultCodeHandler.php deleted file mode 100644 index c9f502c2..00000000 --- a/Components/Adyen/PaymentResultCodeHandler.php +++ /dev/null @@ -1,34 +0,0 @@ -basketService = $basketService; - } - - public function __invoke(array $paymentResponseInfo): void - { - try { - PaymentResultCodes::load($paymentResponseInfo['resultCode']); - } catch (\InvalidArgumentException $exception) { - $this->handlePaymentDataError($paymentResponseInfo); - } - } - - private function handlePaymentDataError(array $paymentResponseInfo): void - { - if (isset($paymentResponseInfo['merchantReference'])) { - $this->basketService->cancelAndRestoreByOrderNumber($paymentResponseInfo['merchantReference']); - } - } -} diff --git a/Components/Adyen/PaymentResultCodeHandlerInterface.php b/Components/Adyen/PaymentResultCodeHandlerInterface.php deleted file mode 100644 index dcc64f86..00000000 --- a/Components/Adyen/PaymentResultCodeHandlerInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -adyenCheckout = $this->get(PaymentMethodService::class); $this->logger = $this->get('adyen_payment.logger'); $this->paymentPayloadProvider = $this->get(PaymentPayloadProvider::class); - $this->paymentResultCodeHandler = $this->get(PaymentResultCodeHandlerInterface::class); + $this->basketService = $this->get(BasketService::class); } public function ajaxDoPaymentAction(): void @@ -53,7 +54,8 @@ public function ajaxDoPaymentAction(): void $context->getTransaction(), $paymentInfo['paymentData'] ?? '' ); - ($this->paymentResultCodeHandler)($paymentInfo); + + $this->handlePaymentData($paymentInfo); $this->Response()->setBody(json_encode( [ @@ -216,4 +218,38 @@ private function getShopperInfo(): array 'shopperIP' => $this->request->getClientIp(), ]; } + + /** + * @param $paymentInfo + * + * @throws Enlight_Event_Exception + * @throws Enlight_Exception + * @throws Zend_Db_Adapter_Exception + * @throws \Doctrine\ORM\ORMException + * @throws \Doctrine\ORM\OptimisticLockException + */ + private function handlePaymentData($paymentInfo): void + { + try { + PaymentResultCodes::load($paymentInfo['resultCode']); + } catch (\InvalidArgumentException $exception) { + $this->handlePaymentDataError($paymentInfo); + } + } + + /** + * @param $paymentInfo + * + * @throws Enlight_Event_Exception + * @throws Enlight_Exception + * @throws Zend_Db_Adapter_Exception + * @throws \Doctrine\ORM\ORMException + * @throws \Doctrine\ORM\OptimisticLockException + */ + private function handlePaymentDataError(array $paymentResponseInfo): void + { + if (array_key_exists('merchantReference', $paymentResponseInfo)) { + $this->basketService->cancelAndRestoreByOrderNumber($paymentResponseInfo['merchantReference']); + } + } } diff --git a/Controllers/Frontend/Process.php b/Controllers/Frontend/Process.php index 3e79894f..18ea1504 100644 --- a/Controllers/Frontend/Process.php +++ b/Controllers/Frontend/Process.php @@ -4,6 +4,7 @@ use AdyenPayment\Components\Adyen\PaymentMethodService; use AdyenPayment\Components\BasketService; use AdyenPayment\Components\Manager\AdyenManager; +use AdyenPayment\Components\Manager\OrderManager; use AdyenPayment\Components\Manager\OrderManagerInterface; use AdyenPayment\Components\OrderMailService; use AdyenPayment\Models\PaymentResultCodes; @@ -49,7 +50,7 @@ public function preDispatch() $this->basketService = $this->get(BasketService::class); $this->orderMailService = $this->get(OrderMailService::class); $this->logger = $this->get('adyen_payment.logger'); - $this->orderManager = $this->get(OrderManagerInterface::class); + $this->orderManager = $this->get(OrderManager::class); $this->snippets = $this->get('snippets'); $this->errorMessageProvider = $this->get(ErrorMessageProvider::class); } diff --git a/Models/PaymentResultCodes.php b/Models/PaymentResultCodes.php index daa7eb32..a6216a7b 100644 --- a/Models/PaymentResultCodes.php +++ b/Models/PaymentResultCodes.php @@ -42,25 +42,6 @@ public static function load(string $resultCode): self return new self($resultCode); } - /** - * @return array - */ - private function availableResultCodes(): array - { - return [ - self::AUTHORISED, - self::CANCELLED, - self::CHALLENGESHOPPER, - self::ERROR, - self::INVALID, - self::IDENTIFYSHOPPER, - self::PENDING, - self::RECEIVED, - self::REDIRECTSHOPPER, - self::REFUSED, - ]; - } - public static function authorised(): self { return new self(self::AUTHORISED); @@ -110,4 +91,23 @@ public static function refused(): self { return new self(self::REFUSED); } + + /** + * @return array + */ + private function availableResultCodes(): array + { + return [ + self::AUTHORISED, + self::CANCELLED, + self::CHALLENGESHOPPER, + self::ERROR, + self::INVALID, + self::IDENTIFYSHOPPER, + self::PENDING, + self::RECEIVED, + self::REDIRECTSHOPPER, + self::REFUSED, + ]; + } } diff --git a/Resources/services/components.xml b/Resources/services/components.xml index cc0b6e57..adfb0f55 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -177,8 +177,5 @@ - - - diff --git a/tests/Unit/Components/Adyen/PaymentResultCodeHandlerTest.php b/tests/Unit/Components/Adyen/PaymentResultCodeHandlerTest.php deleted file mode 100644 index 046d62d1..00000000 --- a/tests/Unit/Components/Adyen/PaymentResultCodeHandlerTest.php +++ /dev/null @@ -1,84 +0,0 @@ -basketService = $this->prophesize(BasketService::class); - $this->paymentResultCodeHandler = new PaymentResultCodeHandler( - $this->basketService->reveal() - ); - } - - /** @test */ - public function it_is_instance_of_payment_result_code_handler_interface(): void - { - $this->assertInstanceOf( - PaymentResultCodeHandlerInterface::class, - $this->paymentResultCodeHandler - ); - } - - /** - * @dataProvider paymentResponseInfoProvider - * @test - */ - public function it_can_handle_a_known_payment_result_code(array $paymentResponseInfo): void - { - ($this->paymentResultCodeHandler)($paymentResponseInfo); - $this->basketService->cancelAndRestoreByOrderNumber(Argument::cetera())->shouldNotBeCalled(); - } - - public function paymentResponseInfoProvider(): \Generator - { - yield [['resultCode' => PaymentResultCodes::authorised()->resultCode()]]; - yield [['resultCode' => PaymentResultCodes::cancelled()->resultCode()]]; - yield [['resultCode' => PaymentResultCodes::challengeShopper()->resultCode()]]; - yield [['resultCode' => PaymentResultCodes::error()->resultCode()]]; - yield [['resultCode' => PaymentResultCodes::identifyShopper()->resultCode()]]; - yield [['resultCode' => PaymentResultCodes::pending()->resultCode()]]; - yield [['resultCode' => PaymentResultCodes::received()->resultCode()]]; - yield [['resultCode' => PaymentResultCodes::redirectShopper()->resultCode()]]; - yield [['resultCode' => PaymentResultCodes::refused()->resultCode()]]; - } - - /** @test */ - public function it_will_cancel_and_restore_order_number_when_merchant_reference_is_given(): void - { - $paymentResponseInfo = [ - 'resultCode' => 'NOT_KNOWN_RESULT_CODE', - 'merchantReference' => '012345', - ]; - ($this->paymentResultCodeHandler)($paymentResponseInfo); - $this->basketService->cancelAndRestoreByOrderNumber($paymentResponseInfo['merchantReference'])->shouldBeCalledOnce(); - } - - /** @test */ - public function it_will_not_cancel_and_restore_order_number_when_no_merchant_reference_is_given(): void - { - $paymentResponseInfo = [ - 'resultCode' => 'NOT_KNOWN_RESULT_CODE', - ]; - ($this->paymentResultCodeHandler)($paymentResponseInfo); - $this->basketService->cancelAndRestoreByOrderNumber(Argument::cetera())->shouldNotBeCalled(); - } -} From 4a0108fa84868cc6a7c81bdce9234ece386b1966 Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 17 Feb 2022 11:09:44 +0100 Subject: [PATCH 081/136] ASW-476 add extra test cases --- tests/Unit/Models/PaymentResultCodesTest.php | 40 ++++++++++++-------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/tests/Unit/Models/PaymentResultCodesTest.php b/tests/Unit/Models/PaymentResultCodesTest.php index cc8b3c5e..7f781196 100644 --- a/tests/Unit/Models/PaymentResultCodesTest.php +++ b/tests/Unit/Models/PaymentResultCodesTest.php @@ -9,17 +9,39 @@ class PaymentResultCodesTest extends TestCase { + private PaymentResultCodes $paymentResultCodes; + + protected function setUp(): void + { + $this->paymentResultCodes = PaymentResultCodes::authorised(); + } + + /** @test */ + public function it_contains_payment_result_codes(): void + { + $this->assertInstanceOf(PaymentResultCodes::class, $this->paymentResultCodes); + } + + /** @test */ + public function it_can_compare_payment_result_codes_objects(): void + { + $this->assertTrue($this->paymentResultCodes->equals(PaymentResultCodes::authorised())); + $this->assertFalse($this->paymentResultCodes->equals(PaymentResultCodes::invalid())); + } + /** @test */ - public function it_can_construct_through_named_constructor(): void + public function it_checks_payment_result_codes_on_immutabillity(): void { - $this->assertInstanceOf(PaymentResultCodes::class, PaymentResultCodes::authorised()); + $paymentResultCodeAuthorised = PaymentResultCodes::authorised(); + $this->assertEquals($this->paymentResultCodes, $paymentResultCodeAuthorised); + $this->assertNotSame($this->paymentResultCodes, $paymentResultCodeAuthorised); } /** * @dataProvider resultCodeProvider * @test */ - public function it_contains_result_code(PaymentResultCodes $resultCode, string $code): void + public function it_can_be_constructed_with_named_constructors(PaymentResultCodes $resultCode, string $code): void { $this->assertEquals($code, $resultCode->resultCode()); } @@ -47,18 +69,6 @@ public function it_throws_an_invalid_argument_exception_when_result_code_is_unkn PaymentResultCodes::load('test'); } - /** @test */ - public function it_can_check_it_is_equal_to_another_value_object(): void - { - $this->assertTrue(PaymentResultCodes::authorised()->equals(PaymentResultCodes::authorised())); - } - - /** @test */ - public function it_can_check_it_is_not_equal_to_another_value_object(): void - { - $this->assertFalse(PaymentResultCodes::authorised()->equals(PaymentResultCodes::cancelled())); - } - /** @test */ public function it_can_load_a_result_code(): void { From ef2bc79ffa0b543006c17a85c3359be0e8031e61 Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 17 Feb 2022 12:55:11 +0100 Subject: [PATCH 082/136] ASW-470 refactor so it uses uuid tokens --- .../RecurringPaymentToken.php | 22 ++++++-- Models/TokenIdentifier.php | 38 +++++++++++++ Recurring/Mapper/RecurringTokenMapper.php | 2 + .../RecurringPaymentTokenTest.php | 18 ++++++ tests/Unit/Models/TokenIdentifierTest.php | 55 +++++++++++++++++++ 5 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 Models/TokenIdentifier.php create mode 100644 tests/Unit/Models/TokenIdentifierTest.php diff --git a/Models/RecurringPayment/RecurringPaymentToken.php b/Models/RecurringPayment/RecurringPaymentToken.php index 45883a93..a8f67e8b 100644 --- a/Models/RecurringPayment/RecurringPaymentToken.php +++ b/Models/RecurringPayment/RecurringPaymentToken.php @@ -5,6 +5,7 @@ namespace AdyenPayment\Models\RecurringPayment; use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Models\TokenIdentifier; use Doctrine\ORM\Mapping as ORM; use Shopware\Components\Model\ModelEntity; @@ -19,11 +20,14 @@ class RecurringPaymentToken extends ModelEntity { /** - * @ORM\Column(name="id", type="integer", nullable=false) - * @ORM\Id - * @ORM\GeneratedValue(strategy="IDENTITY") + * @ORM\Column(name="id", type="string", nullable=false) */ - private int $id; + private string $id; + + /** + * @ORM\Column(name="token_identifier", type="string", nullable=false) + */ + private TokenIdentifier $tokenIdentifier; /** * @ORM\Column(name="customer_id", type="string", length=255, nullable=false) @@ -77,6 +81,7 @@ private function __construct() } public static function create( + TokenIdentifier $id, string $customerId, string $recurringDetailReference, string $pspReference, @@ -86,6 +91,8 @@ public static function create( string $amountCurrency ): self { $new = new self(); + $new->id = $id->identifier(); + $new->tokenIdentifier = $id; $new->customerId = $customerId; $new->recurringDetailReference = $recurringDetailReference; $new->pspReference = $pspReference; @@ -97,11 +104,16 @@ public static function create( return $new; } - public function getId(): int + public function id(): string { return $this->id; } + public function tokenIdentifier(): TokenIdentifier + { + return $this->tokenIdentifier = TokenIdentifier::generateFromString($this->id); + } + public function customerId(): string { return $this->customerId; diff --git a/Models/TokenIdentifier.php b/Models/TokenIdentifier.php new file mode 100644 index 00000000..ffc5b5e5 --- /dev/null +++ b/Models/TokenIdentifier.php @@ -0,0 +1,38 @@ +tokenId = $tokenId; + } + + public static function generate(): TokenIdentifier + { + return new self(Uuid::uuid4()); + } + + public static function generateFromString(string $uuid): TokenIdentifier + { + return new self(Uuid::fromString($uuid)); + } + + public function identifier(): string + { + return $this->tokenId->toString(); + } + + public function equals(TokenIdentifier $id): bool + { + return $id->identifier() === $this->identifier(); + } +} diff --git a/Recurring/Mapper/RecurringTokenMapper.php b/Recurring/Mapper/RecurringTokenMapper.php index 8ac9defe..fba4000b 100644 --- a/Recurring/Mapper/RecurringTokenMapper.php +++ b/Recurring/Mapper/RecurringTokenMapper.php @@ -7,6 +7,7 @@ use AdyenPayment\Exceptions\InvalidPaymentsResponseException; use AdyenPayment\Models\PaymentResultCodes; use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; +use AdyenPayment\Models\TokenIdentifier; final class RecurringTokenMapper implements RecurringTokenMapperInterface { @@ -17,6 +18,7 @@ public function __invoke(array $rawData): RecurringPaymentToken } return RecurringPaymentToken::create( + TokenIdentifier::generate(), $rawData['additionalData']['recurring.shopperReference'] ?? '', $rawData['additionalData']['recurring.recurringDetailReference'] ?? '', $rawData['pspReference'] ?? '', diff --git a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php index cdb1d8a4..fae0a792 100644 --- a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php +++ b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php @@ -6,6 +6,7 @@ use AdyenPayment\Models\PaymentResultCodes; use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; +use AdyenPayment\Models\TokenIdentifier; use PHPUnit\Framework\TestCase; use Shopware\Components\Model\ModelEntity; @@ -16,6 +17,7 @@ class RecurringPaymentTokenTest extends TestCase protected function setUp(): void { $this->recurringPaymentToken = RecurringPaymentToken::create( + $tokenIdentifier = TokenIdentifier::generateFromString($knownUuid = '033a6dad-5a58-4b74-b420-6772bab3946e'), $customerId = 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', $recurringDetailReference = '8415698462516992', $pspReference = '8515815919501547', @@ -32,6 +34,21 @@ public function it_is_a_model_entity(): void $this->assertInstanceOf(ModelEntity::class, $this->recurringPaymentToken); } + /** @test */ + public function it_contains_an_id(): void + { + $this->assertEquals('033a6dad-5a58-4b74-b420-6772bab3946e', $this->recurringPaymentToken->id()); + } + + /** @test */ + public function it_contains_a_token_identifier(): void + { + $this->assertEquals( + TokenIdentifier::generateFromString('033a6dad-5a58-4b74-b420-6772bab3946e'), + $this->recurringPaymentToken->tokenIdentifier() + ); + } + /** @test */ public function it_contains_a_customer_id(): void { @@ -107,6 +124,7 @@ public function it_knows_when_it_is_a_one_off_payment(): void public function it_knows_when_it_is_a_subscription(): void { $recurringPaymentTokenOrderNumberEmpty = RecurringPaymentToken::create( + TokenIdentifier::generateFromString($uuid = 'f958e8a5-c707-4901-91dd-0e16b22b898c'), 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', '8415698462516992', '8515815919501547', diff --git a/tests/Unit/Models/TokenIdentifierTest.php b/tests/Unit/Models/TokenIdentifierTest.php new file mode 100644 index 00000000..544a5402 --- /dev/null +++ b/tests/Unit/Models/TokenIdentifierTest.php @@ -0,0 +1,55 @@ +tokenIdentifier = TokenIdentifier::generateFromString($this->knownUuid); + } + + /** @test */ + public function it_contains_a_token_identifier(): void + { + $this->assertInstanceOf(TokenIdentifier::class, $this->tokenIdentifier); + } + + /** @test */ + public function it_can_compare_token_identifier_objects(): void + { + $this->assertTrue($this->tokenIdentifier->equals(TokenIdentifier::generateFromString($this->knownUuid))); + $this->assertFalse($this->tokenIdentifier->equals(TokenIdentifier::generate())); + } + + /** @test */ + public function it_checks_token_identifier_on_immutabillity(): void + { + $tokenIdentifier = TokenIdentifier::generateFromString($this->knownUuid); + $this->assertEquals($this->tokenIdentifier, $tokenIdentifier); + $this->assertNotSame($this->tokenIdentifier, $tokenIdentifier); + } + + /** + * @dataProvider tokenIdentifierProvider + * @test + */ + public function it_can_be_constructed_with_named_constructors(TokenIdentifier $tokenIdentifier, string $expected): void + { + $this->assertEquals($expected, $tokenIdentifier->identifier()); + } + + public function tokenIdentifierProvider(): \Generator + { + yield [TokenIdentifier::generateFromString('af55ecab-90db-4501-ba7d-9eef61ac3ee3'), 'af55ecab-90db-4501-ba7d-9eef61ac3ee3']; + yield [$randomGenerated = TokenIdentifier::generate(), $randomGenerated->identifier()]; + } +} From 0c9853d0a942593134bd8d83c657d2351b4c17bc Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 17 Feb 2022 15:50:51 +0100 Subject: [PATCH 083/136] ASW-470 id strategy none --- Models/RecurringPayment/RecurringPaymentToken.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Models/RecurringPayment/RecurringPaymentToken.php b/Models/RecurringPayment/RecurringPaymentToken.php index a8f67e8b..1baf6238 100644 --- a/Models/RecurringPayment/RecurringPaymentToken.php +++ b/Models/RecurringPayment/RecurringPaymentToken.php @@ -21,6 +21,8 @@ class RecurringPaymentToken extends ModelEntity { /** * @ORM\Column(name="id", type="string", nullable=false) + * @ORM\Id + * @ORM\GeneratedValue(strategy="NONE") */ private string $id; From c16826b2bba8c214da57f76b447fa48c55fa3992 Mon Sep 17 00:00:00 2001 From: davebueds Date: Thu, 17 Feb 2022 15:57:12 +0100 Subject: [PATCH 084/136] ASW-471 WIP add RecurringPaymentTokenRepository --- ...RecurringPaymentTokenNotFoundException.php | 28 ++++++++ ...RecurringPaymentTokenNotSavedException.php | 17 +++++ .../RecurringPaymentTokenRepository.php | 71 +++++++++++++++++++ ...curringPaymentTokenRepositoryInterface.php | 13 ++++ ...aceableRecurringPaymentTokenRepository.php | 9 +++ 5 files changed, 138 insertions(+) create mode 100644 Exceptions/RecurringPaymentTokenNotFoundException.php create mode 100644 Exceptions/RecurringPaymentTokenNotSavedException.php create mode 100644 Models/RecurringPayment/RecurringPaymentTokenRepository.php create mode 100644 Models/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php create mode 100644 Models/RecurringPayment/TraceableRecurringPaymentTokenRepository.php diff --git a/Exceptions/RecurringPaymentTokenNotFoundException.php b/Exceptions/RecurringPaymentTokenNotFoundException.php new file mode 100644 index 00000000..4dc788fa --- /dev/null +++ b/Exceptions/RecurringPaymentTokenNotFoundException.php @@ -0,0 +1,28 @@ +resultCode(), + $pspReference + )); + } +} diff --git a/Exceptions/RecurringPaymentTokenNotSavedException.php b/Exceptions/RecurringPaymentTokenNotSavedException.php new file mode 100644 index 00000000..95e68a66 --- /dev/null +++ b/Exceptions/RecurringPaymentTokenNotSavedException.php @@ -0,0 +1,17 @@ +identifier().' could not be saved.' + ); + } +} diff --git a/Models/RecurringPayment/RecurringPaymentTokenRepository.php b/Models/RecurringPayment/RecurringPaymentTokenRepository.php new file mode 100644 index 00000000..7a6c338e --- /dev/null +++ b/Models/RecurringPayment/RecurringPaymentTokenRepository.php @@ -0,0 +1,71 @@ +recurringPaymentTokenRepository = $manager->getRepository(RecurringPaymentToken::class); + } + + public function save(RecurringPaymentToken $recurringPaymentToken): void + { + try { + $this->recurringPaymentTokenRepository->persist($recurringPaymentToken); + $this->recurringPaymentTokenRepository->flush(); + } catch (ORMException|ORMInvalidArgumentException $exception) { + throw RecurringPaymentTokenNotSavedException::withId($recurringPaymentToken->tokenIdentifier()); + } + } + + public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orderNumber): RecurringPaymentToken + { + $recurringPaymentToken = $this->recurringPaymentTokenRepository->findBy([ + 'customerId' => $customerId, + 'orderNumber' => $orderNumber, + ]); + + if (!$recurringPaymentToken) { + throw RecurringPaymentTokenNotFoundException::withCustomerIdAndOrderNumber($customerId, $orderNumber); + } + + return $recurringPaymentToken; + } + + public function fetchPendingByPspReference(string $pspReference): RecurringPaymentToken + { + $recurringPaymentToken = $this->recurringPaymentTokenRepository->findBy([ + 'resultCode' => PaymentResultCodes::pending()->resultCode(), + 'pspReference' => $pspReference, + ]); + + if (!$recurringPaymentToken) { + throw RecurringPaymentTokenNotFoundException::withPendingResultCodeAndPspReference($pspReference); + } + + return $recurringPaymentToken; + } + + public function update(RecurringPaymentToken $recurringPaymentToken): void + { + try { + $this->recurringPaymentTokenRepository->persist($recurringPaymentToken); + $this->recurringPaymentTokenRepository->flush(); + } catch (ORMException|ORMInvalidArgumentException $exception) { + throw RecurringPaymentTokenNotSavedException::withId($recurringPaymentToken->tokenIdentifier()); + } + } +} diff --git a/Models/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php b/Models/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php new file mode 100644 index 00000000..25ef6afe --- /dev/null +++ b/Models/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php @@ -0,0 +1,13 @@ + Date: Thu, 17 Feb 2022 16:58:05 +0100 Subject: [PATCH 085/136] ASW-471 add config and traceable recurring payment token repository --- .../RecurringPaymentTokenRepository.php | 4 +- ...aceableRecurringPaymentTokenRepository.php | 55 ++++++++++++++++++- Resources/services/repositories.xml | 10 ++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/Models/RecurringPayment/RecurringPaymentTokenRepository.php b/Models/RecurringPayment/RecurringPaymentTokenRepository.php index 7a6c338e..04124a7d 100644 --- a/Models/RecurringPayment/RecurringPaymentTokenRepository.php +++ b/Models/RecurringPayment/RecurringPaymentTokenRepository.php @@ -38,7 +38,7 @@ public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orde 'orderNumber' => $orderNumber, ]); - if (!$recurringPaymentToken) { + if (!$recurringPaymentToken instanceof RecurringPaymentToken) { throw RecurringPaymentTokenNotFoundException::withCustomerIdAndOrderNumber($customerId, $orderNumber); } @@ -52,7 +52,7 @@ public function fetchPendingByPspReference(string $pspReference): RecurringPayme 'pspReference' => $pspReference, ]); - if (!$recurringPaymentToken) { + if (!$recurringPaymentToken instanceof RecurringPaymentToken) { throw RecurringPaymentTokenNotFoundException::withPendingResultCodeAndPspReference($pspReference); } diff --git a/Models/RecurringPayment/TraceableRecurringPaymentTokenRepository.php b/Models/RecurringPayment/TraceableRecurringPaymentTokenRepository.php index cfa9a66b..03df9736 100644 --- a/Models/RecurringPayment/TraceableRecurringPaymentTokenRepository.php +++ b/Models/RecurringPayment/TraceableRecurringPaymentTokenRepository.php @@ -4,6 +4,59 @@ namespace AdyenPayment\Models\RecurringPayment; -class TraceableRecurringPaymentTokenRepository +use AdyenPayment\Exceptions\RecurringPaymentTokenNotFoundException; +use Doctrine\ORM\ORMException; +use Doctrine\ORM\ORMInvalidArgumentException; +use Psr\Log\LoggerInterface; + +final class TraceableRecurringPaymentTokenRepository implements RecurringPaymentTokenRepositoryInterface { + private RecurringPaymentTokenRepositoryInterface $recurringPaymentTokenRepository; + private LoggerInterface $logger; + + public function __construct( + RecurringPaymentTokenRepositoryInterface $recurringPaymentTokenRepository, + LoggerInterface $logger + ) { + $this->recurringPaymentTokenRepository = $recurringPaymentTokenRepository; + $this->logger = $logger; + } + + public function save(RecurringPaymentToken $recurringPaymentToken): void + { + try { + $this->recurringPaymentTokenRepository->save($recurringPaymentToken); + } catch (ORMException|ORMInvalidArgumentException $exception) { + $this->logger->error($exception->getMessage(), ['exception' => $exception]); + } + } + + public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orderNumber): RecurringPaymentToken + { + try { + return $this->recurringPaymentTokenRepository->fetchByCustomerIdAndOrderNumber($customerId, $orderNumber); + } catch (RecurringPaymentTokenNotFoundException $exception) { + $this->logger->info($exception->getMessage(), ['exception' => $exception]); + throw $exception; + } + } + + public function fetchPendingByPspReference(string $pspReference): RecurringPaymentToken + { + try { + return $this->recurringPaymentTokenRepository->fetchPendingByPspReference($pspReference); + } catch (RecurringPaymentTokenNotFoundException $exception) { + $this->logger->info($exception->getMessage(), ['exception' => $exception]); + throw $exception; + } + } + + public function update(RecurringPaymentToken $recurringPaymentToken): void + { + try { + $this->recurringPaymentTokenRepository->update($recurringPaymentToken); + } catch (ORMException|ORMInvalidArgumentException $exception) { + $this->logger->error($exception->getMessage(), ['exception' => $exception]); + } + } } diff --git a/Resources/services/repositories.xml b/Resources/services/repositories.xml index 4a1bd5fc..81a1df2a 100644 --- a/Resources/services/repositories.xml +++ b/Resources/services/repositories.xml @@ -7,6 +7,16 @@
+ + + + + + + + + From c23f0474c2a6b744a6c0079cafd2e155181380d3 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 22 Feb 2022 10:59:36 +0100 Subject: [PATCH 086/136] ASW-473 - CR fixes --- .../RecurringProcessingModel.php | 6 ++-- .../RecurringProcessingModelTest.php | 36 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Models/RecurringPayment/RecurringProcessingModel.php b/Models/RecurringPayment/RecurringProcessingModel.php index 9df5ac03..72c8b292 100644 --- a/Models/RecurringPayment/RecurringProcessingModel.php +++ b/Models/RecurringPayment/RecurringProcessingModel.php @@ -6,7 +6,7 @@ final class RecurringProcessingModel { - private const CARDONFILE = 'CardOnFile'; + private const CARD_ON_FILE = 'CardOnFile'; private const SUBSCRIPTION = 'Subscription'; private const UNSCHEDULED_CARD_ON_FILE = 'UnscheduledCardOnFile'; private string $recurringProcessingModel; @@ -37,7 +37,7 @@ public static function load(string $recurringProcessingModel): self public static function cardOnFile(): self { - return new self(self::CARDONFILE); + return new self(self::CARD_ON_FILE); } public static function subscription(): self @@ -48,7 +48,7 @@ public static function subscription(): self private function availableRecurringProcessingModels(): array { return [ - self::CARDONFILE, + self::CARD_ON_FILE, self::SUBSCRIPTION, self::UNSCHEDULED_CARD_ON_FILE, ]; diff --git a/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php b/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php index b49bf970..05f8f532 100644 --- a/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php +++ b/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php @@ -23,36 +23,20 @@ public function it_contains_a_recurring_processing_model(): void } /** @test */ - public function it_can_compare_recurring_processing_model_objects(): void + public function it_knows_when_it_equals_a_processing_model(): void { $this->assertTrue($this->recurringProcessingModel->equals(RecurringProcessingModel::cardOnFile())); $this->assertFalse($this->recurringProcessingModel->equals(RecurringProcessingModel::subscription())); } /** @test */ - public function it_checks_recurring_processing_model_on_immutabillity(): void + public function it_is_a_recurring_processing_model(): void { $recurringProcessingModel = RecurringProcessingModel::cardOnFile(); $this->assertEquals($this->recurringProcessingModel, $recurringProcessingModel); $this->assertNotSame($this->recurringProcessingModel, $recurringProcessingModel); } - /** - * @dataProvider recurringProcessingModelProvider - * @test - */ - public function it_contains_recurring_processing_model( - RecurringProcessingModel $recurringProcessingModel, string $expected - ): void { - $this->assertEquals($expected, $recurringProcessingModel->recurringProcessingModel()); - } - - public function recurringProcessingModelProvider(): \Generator - { - yield [RecurringProcessingModel::cardOnFile(), 'CardOnFile']; - yield [RecurringProcessingModel::subscription(), 'Subscription']; - } - /** @test */ public function it_throws_an_invalid_argument_exception_when_recurring_processing_model_is_unknown(): void { @@ -70,4 +54,20 @@ public function it_can_load_a_recurring_processing_model(): void RecurringProcessingModel::load('CardOnFile') ); } + + /** + * @dataProvider recurringProcessingModelProvider + * @test + */ + public function it_contains_recurring_processing_model( + RecurringProcessingModel $recurringProcessingModel, string $expected + ): void { + $this->assertEquals($expected, $recurringProcessingModel->recurringProcessingModel()); + } + + public function recurringProcessingModelProvider(): \Generator + { + yield [RecurringProcessingModel::cardOnFile(), 'CardOnFile']; + yield [RecurringProcessingModel::subscription(), 'Subscription']; + } } From 62d6eae63ecf42a46f45ae1f091551d0b2ffb2b5 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 25 Feb 2022 11:28:43 +0100 Subject: [PATCH 087/136] ASW-473 - CR fix --- .../Models/RecurringPayment/RecurringProcessingModelTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php b/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php index 05f8f532..861df387 100644 --- a/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php +++ b/tests/Unit/Models/RecurringPayment/RecurringProcessingModelTest.php @@ -30,7 +30,7 @@ public function it_knows_when_it_equals_a_processing_model(): void } /** @test */ - public function it_is_a_recurring_processing_model(): void + public function it_knows_when_it_equals_a_recurring_processing_model(): void { $recurringProcessingModel = RecurringProcessingModel::cardOnFile(); $this->assertEquals($this->recurringProcessingModel, $recurringProcessingModel); From 542892b1bfbc8b556077dc012c1c5f15bd18c10a Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 22 Feb 2022 11:31:12 +0100 Subject: [PATCH 088/136] ASW-476 - CR fixes --- Controllers/Frontend/Adyen.php | 8 ++++---- Models/PaymentResultCodes.php | 27 ++++++++++++++++----------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Controllers/Frontend/Adyen.php b/Controllers/Frontend/Adyen.php index cd1af59a..37c0a303 100644 --- a/Controllers/Frontend/Adyen.php +++ b/Controllers/Frontend/Adyen.php @@ -230,11 +230,11 @@ private function getShopperInfo(): array */ private function handlePaymentData($paymentInfo): void { - try { - PaymentResultCodes::load($paymentInfo['resultCode']); - } catch (\InvalidArgumentException $exception) { - $this->handlePaymentDataError($paymentInfo); + if (PaymentResultCodes::exists((string) ($paymentInfo['resultCode'] ?? ''))) { + return; } + + $this->handlePaymentDataError($paymentInfo); } /** diff --git a/Models/PaymentResultCodes.php b/Models/PaymentResultCodes.php index a6216a7b..8954167a 100644 --- a/Models/PaymentResultCodes.php +++ b/Models/PaymentResultCodes.php @@ -8,19 +8,19 @@ final class PaymentResultCodes { private const AUTHORISED = 'Authorised'; private const CANCELLED = 'Cancelled'; - private const CHALLENGESHOPPER = 'ChallengeShopper'; + private const CHALLENGE_SHOPPER = 'ChallengeShopper'; private const ERROR = 'Error'; - private const IDENTIFYSHOPPER = 'IdentifyShopper'; + private const IDENTIFY_SHOPPER = 'IdentifyShopper'; private const INVALID = 'Invalid'; private const PENDING = 'Pending'; private const RECEIVED = 'Received'; - private const REDIRECTSHOPPER = 'RedirectShopper'; + private const REDIRECT_SHOPPER = 'RedirectShopper'; private const REFUSED = 'Refused'; private string $resultCode; private function __construct(string $resultCode) { - if (!in_array($resultCode, $this->availableResultCodes(), true)) { + if (!self::exists($resultCode)) { throw new \InvalidArgumentException('Invalid result code: "'.$resultCode.'"'); } @@ -42,6 +42,11 @@ public static function load(string $resultCode): self return new self($resultCode); } + public static function exists(string $resultCode): bool + { + return in_array($resultCode, self::availableResultCodes(), true); + } + public static function authorised(): self { return new self(self::AUTHORISED); @@ -49,7 +54,7 @@ public static function authorised(): self public static function challengeShopper(): self { - return new self(self::CHALLENGESHOPPER); + return new self(self::CHALLENGE_SHOPPER); } public static function cancelled(): self @@ -69,7 +74,7 @@ public static function invalid(): self public static function identifyShopper(): self { - return new self(self::IDENTIFYSHOPPER); + return new self(self::IDENTIFY_SHOPPER); } public static function pending(): self @@ -84,7 +89,7 @@ public static function received(): self public static function redirectShopper(): self { - return new self(self::REDIRECTSHOPPER); + return new self(self::REDIRECT_SHOPPER); } public static function refused(): self @@ -95,18 +100,18 @@ public static function refused(): self /** * @return array */ - private function availableResultCodes(): array + private static function availableResultCodes(): array { return [ self::AUTHORISED, self::CANCELLED, - self::CHALLENGESHOPPER, + self::CHALLENGE_SHOPPER, self::ERROR, self::INVALID, - self::IDENTIFYSHOPPER, + self::IDENTIFY_SHOPPER, self::PENDING, self::RECEIVED, - self::REDIRECTSHOPPER, + self::REDIRECT_SHOPPER, self::REFUSED, ]; } From 22285aef7bfd0fa9dc863d431b4a96845f1ee53d Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 24 Feb 2022 12:21:46 +0100 Subject: [PATCH 089/136] ASW-476 - CR fixes --- tests/Unit/Models/PaymentResultCodesTest.php | 62 ++++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/tests/Unit/Models/PaymentResultCodesTest.php b/tests/Unit/Models/PaymentResultCodesTest.php index 7f781196..0b857464 100644 --- a/tests/Unit/Models/PaymentResultCodesTest.php +++ b/tests/Unit/Models/PaymentResultCodesTest.php @@ -17,26 +17,54 @@ protected function setUp(): void } /** @test */ - public function it_contains_payment_result_codes(): void - { - $this->assertInstanceOf(PaymentResultCodes::class, $this->paymentResultCodes); - } - - /** @test */ - public function it_can_compare_payment_result_codes_objects(): void + public function it_knows_when_it_equals_payment_result_codes_objects(): void { $this->assertTrue($this->paymentResultCodes->equals(PaymentResultCodes::authorised())); $this->assertFalse($this->paymentResultCodes->equals(PaymentResultCodes::invalid())); } /** @test */ - public function it_checks_payment_result_codes_on_immutabillity(): void + public function it_is_immutable_constructed(): void { $paymentResultCodeAuthorised = PaymentResultCodes::authorised(); $this->assertEquals($this->paymentResultCodes, $paymentResultCodeAuthorised); $this->assertNotSame($this->paymentResultCodes, $paymentResultCodeAuthorised); } + /** @test */ + public function it_throws_an_invalid_argument_exception_when_result_code_is_unknown(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid result code: "test"'); + + PaymentResultCodes::load('test'); + } + + /** @test */ + public function it_can_load_a_result_code(): void + { + $this->assertEquals( + PaymentResultCodes::authorised(), + PaymentResultCodes::load('Authorised') + ); + } + + /** @test */ + public function it_knows_when_a_result_code_exists(): void + { + $result = PaymentResultCodes::exists(PaymentResultCodes::cancelled()->resultCode()); + + $this->assertTrue($result); + } + + /** @test */ + public function it_knows_when_a_result_code_doesnt_exists(): void + { + $result = PaymentResultCodes::exists('invalid-code-test'); + + $this->assertFalse($result); + } + /** * @dataProvider resultCodeProvider * @test @@ -59,22 +87,4 @@ public function resultCodeProvider(): \Generator yield [PaymentResultCodes::redirectShopper(), 'RedirectShopper']; yield [PaymentResultCodes::refused(), 'Refused']; } - - /** @test */ - public function it_throws_an_invalid_argument_exception_when_result_code_is_unknown(): void - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid result code: "test"'); - - PaymentResultCodes::load('test'); - } - - /** @test */ - public function it_can_load_a_result_code(): void - { - $this->assertEquals( - PaymentResultCodes::authorised(), - PaymentResultCodes::load('Authorised') - ); - } } From e93a00233c8c2398ac86acd7e613c09c9d5143e4 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 22 Feb 2022 11:40:31 +0100 Subject: [PATCH 090/136] ASW-469 - CR fixes --- .../InvalidPaymentsResponseException.php | 2 +- Recurring/Mapper/RecurringTokenMapper.php | 4 +-- .../Mapper/RecurringTokenMapperTest.php | 36 ------------------- 3 files changed, 3 insertions(+), 39 deletions(-) diff --git a/Exceptions/InvalidPaymentsResponseException.php b/Exceptions/InvalidPaymentsResponseException.php index 7ffd3c1f..9471c296 100644 --- a/Exceptions/InvalidPaymentsResponseException.php +++ b/Exceptions/InvalidPaymentsResponseException.php @@ -6,7 +6,7 @@ class InvalidPaymentsResponseException extends \Exception { - public static function missingPaymentsResponseContent(): self + public static function invalid(): self { return new static('Payments response not found.'); } diff --git a/Recurring/Mapper/RecurringTokenMapper.php b/Recurring/Mapper/RecurringTokenMapper.php index fba4000b..7dc0bc53 100644 --- a/Recurring/Mapper/RecurringTokenMapper.php +++ b/Recurring/Mapper/RecurringTokenMapper.php @@ -13,8 +13,8 @@ final class RecurringTokenMapper implements RecurringTokenMapperInterface { public function __invoke(array $rawData): RecurringPaymentToken { - if (!$rawData) { - throw InvalidPaymentsResponseException::missingPaymentsResponseContent(); + if (0 === count($rawData)) { + throw InvalidPaymentsResponseException::invalid(); } return RecurringPaymentToken::create( diff --git a/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php b/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php index 1378619d..057e34fc 100644 --- a/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php +++ b/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php @@ -85,40 +85,4 @@ public function it_can_map_default_values(): void $this->assertEquals(0, $recurringPaymentToken->amountValue()); $this->assertEquals('', $recurringPaymentToken->amountCurrency()); } - - /** @test */ - public function it_maps_empty_string_when_additional_data_not_in_response(): void - { - $adyenPaymentsResponseArray = [ - 'pspReference' => '8515815919501547', - 'resultCode' => 'Authorised', - 'amount' => [ - 'currency' => 'USD', - 'value' => 0, - ], - 'merchantReference' => 'YOUR_ORDER_NUMBER', - ]; - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenPaymentsResponseArray); - - $this->assertEquals('', $recurringPaymentToken->customerId()); - $this->assertEquals('', $recurringPaymentToken->recurringDetailReference()); - } - - /** @test */ - public function it_maps_to_empty_string_and_zero_when_amount_not_in_response(): void - { - $adyenPaymentsResponseArray = [ - 'additionalData' => [ - 'recurring.recurringDetailReference' => '8415698462516992', - 'recurring.shopperReference' => 'YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', - ], - 'pspReference' => '8515815919501547', - 'resultCode' => 'Authorised', - 'merchantReference' => 'YOUR_ORDER_NUMBER', - ]; - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenPaymentsResponseArray); - - $this->assertEquals(0, $recurringPaymentToken->amountValue()); - $this->assertEquals('', $recurringPaymentToken->amountCurrency()); - } } From ba322e266e3f225aef4b11e9aba83d741c245aa2 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 23 Feb 2022 12:51:21 +0100 Subject: [PATCH 091/136] ASW-471 - CR fixes and unit tests --- Controllers/Frontend/Adyen.php | 4 +- Controllers/Frontend/Process.php | 30 +-- ...RecurringPaymentTokenNotFoundException.php | 10 +- ...RecurringPaymentTokenNotSavedException.php | 6 +- ...tResultCodes.php => PaymentResultCode.php} | 6 +- .../RecurringPaymentToken.php | 4 +- .../RecurringPayment/ShopperInteraction.php | 6 +- Recurring/Mapper/RecurringTokenMapper.php | 6 +- .../RecurringPaymentTokenRepository.php | 35 ++-- ...curringPaymentTokenRepositoryInterface.php | 4 +- ...aceableRecurringPaymentTokenRepository.php | 5 +- Resources/services/repositories.xml | 16 +- ...rringPaymentTokenNotFoundExceptionTest.php | 51 +++++ ...rringPaymentTokenNotSavedExceptionTest.php | 27 +++ tests/Unit/Models/PaymentResultCodeTest.php | 90 ++++++++ tests/Unit/Models/PaymentResultCodesTest.php | 90 -------- .../RecurringPaymentTokenTest.php | 6 +- .../RecurringPaymentTokenRepositoryTest.php | 192 ++++++++++++++++++ 18 files changed, 433 insertions(+), 155 deletions(-) rename Models/{PaymentResultCodes.php => PaymentResultCode.php} (93%) rename {Models => Repository}/RecurringPayment/RecurringPaymentTokenRepository.php (56%) rename {Models => Repository}/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php (79%) rename {Models => Repository}/RecurringPayment/TraceableRecurringPaymentTokenRepository.php (95%) create mode 100644 tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php create mode 100644 tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php create mode 100644 tests/Unit/Models/PaymentResultCodeTest.php delete mode 100644 tests/Unit/Models/PaymentResultCodesTest.php create mode 100644 tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php diff --git a/Controllers/Frontend/Adyen.php b/Controllers/Frontend/Adyen.php index 37c0a303..54477383 100644 --- a/Controllers/Frontend/Adyen.php +++ b/Controllers/Frontend/Adyen.php @@ -4,7 +4,7 @@ use AdyenPayment\AdyenPayment; use AdyenPayment\Components\Adyen\PaymentMethodService; use AdyenPayment\Components\BasketService; -use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Models\PaymentResultCode; use AdyenPayment\Components\Manager\AdyenManager; use AdyenPayment\Components\Payload\Chain; use AdyenPayment\Components\Payload\PaymentContext; @@ -230,7 +230,7 @@ private function getShopperInfo(): array */ private function handlePaymentData($paymentInfo): void { - if (PaymentResultCodes::exists((string) ($paymentInfo['resultCode'] ?? ''))) { + if (PaymentResultCode::exists((string) ($paymentInfo['resultCode'] ?? ''))) { return; } diff --git a/Controllers/Frontend/Process.php b/Controllers/Frontend/Process.php index 18ea1504..887cf4f8 100644 --- a/Controllers/Frontend/Process.php +++ b/Controllers/Frontend/Process.php @@ -7,7 +7,7 @@ use AdyenPayment\Components\Manager\OrderManager; use AdyenPayment\Components\Manager\OrderManagerInterface; use AdyenPayment\Components\OrderMailService; -use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Models\PaymentResultCode; use AdyenPayment\Session\ErrorMessageProvider; use AdyenPayment\Session\MessageProvider; use AdyenPayment\Utils\RequestDataFormatter; @@ -72,10 +72,10 @@ public function returnAction(): void $result = $this->validateResponse($response, $order); $this->handleReturnResult($result, $order); - switch(PaymentResultCodes::load($result['resultCode'])) { - case PaymentResultCodes::authorised(): - case PaymentResultCodes::pending(): - case PaymentResultCodes::received(): + switch(PaymentResultCode::load($result['resultCode'])) { + case PaymentResultCode::authorised(): + case PaymentResultCode::pending(): + case PaymentResultCode::received(): if (!empty($result['merchantReference'])) { $this->orderMailService->sendOrderConfirmationMail($result['merchantReference']); } @@ -86,9 +86,9 @@ public function returnAction(): void 'sAGB' => true, ]); break; - case PaymentResultCodes::cancelled(): - case PaymentResultCodes::error(): - case PaymentResultCodes::refused(): + case PaymentResultCode::cancelled(): + case PaymentResultCode::error(): + case PaymentResultCode::refused(): default: $this->errorMessageProvider->add( $this->snippets->getNamespace('adyen/checkout/error') @@ -123,18 +123,18 @@ private function handleReturnResult(array $result, ?Order $order): void return; } - switch (PaymentResultCodes::load($result['resultCode'])) { - case PaymentResultCodes::authorised(): - case PaymentResultCodes::pending(): - case PaymentResultCodes::received(): + switch (PaymentResultCode::load($result['resultCode'])) { + case PaymentResultCode::authorised(): + case PaymentResultCode::pending(): + case PaymentResultCode::received(): $paymentStatus = $this->getModelManager()->find( Status::class, Status::PAYMENT_STATE_THE_PAYMENT_HAS_BEEN_ORDERED ); break; - case PaymentResultCodes::cancelled(): - case PaymentResultCodes::error(): - case PaymentResultCodes::refused(): + case PaymentResultCode::cancelled(): + case PaymentResultCode::error(): + case PaymentResultCode::refused(): $paymentStatus = $this->getModelManager()->find( Status::class, Status::PAYMENT_STATE_THE_PROCESS_HAS_BEEN_CANCELLED diff --git a/Exceptions/RecurringPaymentTokenNotFoundException.php b/Exceptions/RecurringPaymentTokenNotFoundException.php index 4dc788fa..b0887d73 100644 --- a/Exceptions/RecurringPaymentTokenNotFoundException.php +++ b/Exceptions/RecurringPaymentTokenNotFoundException.php @@ -4,14 +4,14 @@ namespace AdyenPayment\Exceptions; -use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Models\PaymentResultCode; -class RecurringPaymentTokenNotFoundException extends \Exception +final class RecurringPaymentTokenNotFoundException extends \RuntimeException { public static function withCustomerIdAndOrderNumber(string $customerId, string $orderNumber): self { return new self(sprintf( - 'Recurring payment token with customer id: %s and order number: %s could not be found.', + 'Recurring payment token not found with customer id: %s, order number: %s', $customerId, $orderNumber )); @@ -20,8 +20,8 @@ public static function withCustomerIdAndOrderNumber(string $customerId, string $ public static function withPendingResultCodeAndPspReference(string $pspReference): self { return new self(sprintf( - 'Recurring payment token with result code: %s and psp reference: %s could not be found.', - PaymentResultCodes::pending()->resultCode(), + 'Recurring payment token not found with result code: %s, psp reference: %s', + PaymentResultCode::pending()->resultCode(), $pspReference )); } diff --git a/Exceptions/RecurringPaymentTokenNotSavedException.php b/Exceptions/RecurringPaymentTokenNotSavedException.php index 95e68a66..745a446d 100644 --- a/Exceptions/RecurringPaymentTokenNotSavedException.php +++ b/Exceptions/RecurringPaymentTokenNotSavedException.php @@ -6,12 +6,10 @@ use AdyenPayment\Models\TokenIdentifier; -class RecurringPaymentTokenNotSavedException extends \Exception +final class RecurringPaymentTokenNotSavedException extends \RuntimeException { public static function withId(TokenIdentifier $tokenIdentifier): self { - return new self( - 'Recurring payment token with id: '.$tokenIdentifier->identifier().' could not be saved.' - ); + return new self('Recurring payment token not saved with id:'.$tokenIdentifier->identifier()); } } diff --git a/Models/PaymentResultCodes.php b/Models/PaymentResultCode.php similarity index 93% rename from Models/PaymentResultCodes.php rename to Models/PaymentResultCode.php index 8954167a..b37b07be 100644 --- a/Models/PaymentResultCodes.php +++ b/Models/PaymentResultCode.php @@ -4,7 +4,7 @@ namespace AdyenPayment\Models; -final class PaymentResultCodes +final class PaymentResultCode { private const AUTHORISED = 'Authorised'; private const CANCELLED = 'Cancelled'; @@ -32,9 +32,9 @@ public function resultCode(): string return $this->resultCode; } - public function equals(PaymentResultCodes $paymentResultCodes): bool + public function equals(PaymentResultCode $paymentResultCode): bool { - return $paymentResultCodes->resultCode() === $this->resultCode; + return $paymentResultCode->resultCode() === $this->resultCode; } public static function load(string $resultCode): self diff --git a/Models/RecurringPayment/RecurringPaymentToken.php b/Models/RecurringPayment/RecurringPaymentToken.php index 1baf6238..e66dcb1e 100644 --- a/Models/RecurringPayment/RecurringPaymentToken.php +++ b/Models/RecurringPayment/RecurringPaymentToken.php @@ -4,7 +4,7 @@ namespace AdyenPayment\Models\RecurringPayment; -use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Models\PaymentResultCode; use AdyenPayment\Models\TokenIdentifier; use Doctrine\ORM\Mapping as ORM; use Shopware\Components\Model\ModelEntity; @@ -88,7 +88,7 @@ public static function create( string $recurringDetailReference, string $pspReference, string $orderNumber, - PaymentResultCodes $resultCode, + PaymentResultCode $resultCode, int $amountValue, string $amountCurrency ): self { diff --git a/Models/RecurringPayment/ShopperInteraction.php b/Models/RecurringPayment/ShopperInteraction.php index bf219000..6e8d0c72 100644 --- a/Models/RecurringPayment/ShopperInteraction.php +++ b/Models/RecurringPayment/ShopperInteraction.php @@ -6,7 +6,7 @@ final class ShopperInteraction { - private const CONTAUTH = 'ContAuth'; + private const CONT_AUTH = 'ContAuth'; private const ECOMMERCE = 'Ecommerce'; private const MOTO = 'Moto'; private const POS = 'POS'; @@ -38,7 +38,7 @@ public static function load(string $shopperInteraction): self public static function contAuth(): self { - return new self(self::CONTAUTH); + return new self(self::CONT_AUTH); } public static function ecommerce(): self @@ -49,7 +49,7 @@ public static function ecommerce(): self private function availableShopperInteractions(): array { return [ - self::CONTAUTH, + self::CONT_AUTH, self::ECOMMERCE, self::MOTO, self::POS, diff --git a/Recurring/Mapper/RecurringTokenMapper.php b/Recurring/Mapper/RecurringTokenMapper.php index 7dc0bc53..4a047089 100644 --- a/Recurring/Mapper/RecurringTokenMapper.php +++ b/Recurring/Mapper/RecurringTokenMapper.php @@ -5,7 +5,7 @@ namespace AdyenPayment\Recurring\Mapper; use AdyenPayment\Exceptions\InvalidPaymentsResponseException; -use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Models\PaymentResultCode; use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; use AdyenPayment\Models\TokenIdentifier; @@ -24,8 +24,8 @@ public function __invoke(array $rawData): RecurringPaymentToken $rawData['pspReference'] ?? '', $rawData['merchantReference'] ?? '', array_key_exists('resultCode', $rawData) ? - PaymentResultCodes::load($rawData['resultCode']) : - PaymentResultCodes::invalid(), + PaymentResultCode::load($rawData['resultCode']) : + PaymentResultCode::invalid(), $rawData['amount']['value'] ?? 0, $rawData['amount']['currency'] ?? '' ); diff --git a/Models/RecurringPayment/RecurringPaymentTokenRepository.php b/Repository/RecurringPayment/RecurringPaymentTokenRepository.php similarity index 56% rename from Models/RecurringPayment/RecurringPaymentTokenRepository.php rename to Repository/RecurringPayment/RecurringPaymentTokenRepository.php index 04124a7d..9b1fc84c 100644 --- a/Models/RecurringPayment/RecurringPaymentTokenRepository.php +++ b/Repository/RecurringPayment/RecurringPaymentTokenRepository.php @@ -2,30 +2,33 @@ declare(strict_types=1); -namespace AdyenPayment\Models\RecurringPayment; +namespace AdyenPayment\Repository\RecurringPayment; use AdyenPayment\Exceptions\RecurringPaymentTokenNotFoundException; use AdyenPayment\Exceptions\RecurringPaymentTokenNotSavedException; -use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Models\PaymentResultCode; +use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityRepository; use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMInvalidArgumentException; -use Shopware\Components\Model\ModelManager; final class RecurringPaymentTokenRepository implements RecurringPaymentTokenRepositoryInterface { - /** @var \Doctrine\ORM\EntityRepository|\Doctrine\Persistence\ObjectRepository|RecurringPaymentTokenRepository */ - private $recurringPaymentTokenRepository; + private EntityManager $entityManager; + private EntityRepository $recurringPaymentTokenEntityRepository; - public function __construct(ModelManager $manager) + public function __construct(EntityManager $entityManager, EntityRepository $recurringPaymentTokenEntityRepository) { - $this->recurringPaymentTokenRepository = $manager->getRepository(RecurringPaymentToken::class); + $this->entityManager = $entityManager; + $this->recurringPaymentTokenEntityRepository = $recurringPaymentTokenEntityRepository; } public function save(RecurringPaymentToken $recurringPaymentToken): void { try { - $this->recurringPaymentTokenRepository->persist($recurringPaymentToken); - $this->recurringPaymentTokenRepository->flush(); + $this->entityManager->persist($recurringPaymentToken); + $this->entityManager->flush($recurringPaymentToken); } catch (ORMException|ORMInvalidArgumentException $exception) { throw RecurringPaymentTokenNotSavedException::withId($recurringPaymentToken->tokenIdentifier()); } @@ -33,12 +36,12 @@ public function save(RecurringPaymentToken $recurringPaymentToken): void public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orderNumber): RecurringPaymentToken { - $recurringPaymentToken = $this->recurringPaymentTokenRepository->findBy([ + $recurringPaymentToken = $this->recurringPaymentTokenEntityRepository->findOneBy([ 'customerId' => $customerId, 'orderNumber' => $orderNumber, ]); - if (!$recurringPaymentToken instanceof RecurringPaymentToken) { + if (!($recurringPaymentToken instanceof RecurringPaymentToken)) { throw RecurringPaymentTokenNotFoundException::withCustomerIdAndOrderNumber($customerId, $orderNumber); } @@ -47,12 +50,12 @@ public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orde public function fetchPendingByPspReference(string $pspReference): RecurringPaymentToken { - $recurringPaymentToken = $this->recurringPaymentTokenRepository->findBy([ - 'resultCode' => PaymentResultCodes::pending()->resultCode(), + $recurringPaymentToken = $this->recurringPaymentTokenEntityRepository->findOneBy([ + 'resultCode' => PaymentResultCode::pending()->resultCode(), 'pspReference' => $pspReference, ]); - if (!$recurringPaymentToken instanceof RecurringPaymentToken) { + if (!($recurringPaymentToken instanceof RecurringPaymentToken)) { throw RecurringPaymentTokenNotFoundException::withPendingResultCodeAndPspReference($pspReference); } @@ -62,8 +65,8 @@ public function fetchPendingByPspReference(string $pspReference): RecurringPayme public function update(RecurringPaymentToken $recurringPaymentToken): void { try { - $this->recurringPaymentTokenRepository->persist($recurringPaymentToken); - $this->recurringPaymentTokenRepository->flush(); + $this->entityManager->persist($recurringPaymentToken); + $this->entityManager->flush($recurringPaymentToken); } catch (ORMException|ORMInvalidArgumentException $exception) { throw RecurringPaymentTokenNotSavedException::withId($recurringPaymentToken->tokenIdentifier()); } diff --git a/Models/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php b/Repository/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php similarity index 79% rename from Models/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php rename to Repository/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php index 25ef6afe..b4f75cf8 100644 --- a/Models/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php +++ b/Repository/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php @@ -2,7 +2,9 @@ declare(strict_types=1); -namespace AdyenPayment\Models\RecurringPayment; +namespace AdyenPayment\Repository\RecurringPayment; + +use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; interface RecurringPaymentTokenRepositoryInterface { diff --git a/Models/RecurringPayment/TraceableRecurringPaymentTokenRepository.php b/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepository.php similarity index 95% rename from Models/RecurringPayment/TraceableRecurringPaymentTokenRepository.php rename to Repository/RecurringPayment/TraceableRecurringPaymentTokenRepository.php index 03df9736..ad94a1e4 100644 --- a/Models/RecurringPayment/TraceableRecurringPaymentTokenRepository.php +++ b/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepository.php @@ -2,9 +2,10 @@ declare(strict_types=1); -namespace AdyenPayment\Models\RecurringPayment; +namespace AdyenPayment\Repository\RecurringPayment; use AdyenPayment\Exceptions\RecurringPaymentTokenNotFoundException; +use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMInvalidArgumentException; use Psr\Log\LoggerInterface; @@ -37,6 +38,7 @@ public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orde return $this->recurringPaymentTokenRepository->fetchByCustomerIdAndOrderNumber($customerId, $orderNumber); } catch (RecurringPaymentTokenNotFoundException $exception) { $this->logger->info($exception->getMessage(), ['exception' => $exception]); + throw $exception; } } @@ -47,6 +49,7 @@ public function fetchPendingByPspReference(string $pspReference): RecurringPayme return $this->recurringPaymentTokenRepository->fetchPendingByPspReference($pspReference); } catch (RecurringPaymentTokenNotFoundException $exception) { $this->logger->info($exception->getMessage(), ['exception' => $exception]); + throw $exception; } } diff --git a/Resources/services/repositories.xml b/Resources/services/repositories.xml index 81a1df2a..27766034 100644 --- a/Resources/services/repositories.xml +++ b/Resources/services/repositories.xml @@ -1,20 +1,22 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + + service('models').getRepository('AdyenPayment\Models\RecurringPayment\RecurringPaymentToken') - - - + + + diff --git a/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php b/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php new file mode 100644 index 00000000..0df12408 --- /dev/null +++ b/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php @@ -0,0 +1,51 @@ +getMessage() + ); + } + + /** @test */ + public function it_can_return_an_exception_with_psp_reference(): void + { + $exception = RecurringPaymentTokenNotFoundException::withPendingResultCodeAndPspReference( + $pspReference = 'psp-reference' + ); + + self::assertInstanceOf(\RuntimeException::class, $exception); + self::assertInstanceOf(RecurringPaymentTokenNotFoundException::class, $exception); + self::assertEquals( + sprintf( + 'Recurring payment token not found with result code: %s, psp reference: %s', + PaymentResultCode::pending()->resultCode(), + $pspReference + ), + $exception->getMessage() + ); + } +} diff --git a/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php b/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php new file mode 100644 index 00000000..d7ac2582 --- /dev/null +++ b/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php @@ -0,0 +1,27 @@ +identifier(), + $exception->getMessage() + ); + } +} diff --git a/tests/Unit/Models/PaymentResultCodeTest.php b/tests/Unit/Models/PaymentResultCodeTest.php new file mode 100644 index 00000000..304d07ce --- /dev/null +++ b/tests/Unit/Models/PaymentResultCodeTest.php @@ -0,0 +1,90 @@ +paymentResultCode = PaymentResultCode::authorised(); + } + + /** @test */ + public function it_knows_when_it_equals_payment_result_codes_objects(): void + { + $this->assertTrue($this->paymentResultCode->equals(PaymentResultCode::authorised())); + $this->assertFalse($this->paymentResultCode->equals(PaymentResultCode::invalid())); + } + + /** @test */ + public function it_is_immutable_constructed(): void + { + $paymentResultCodeAuthorised = PaymentResultCode::authorised(); + $this->assertEquals($this->paymentResultCode, $paymentResultCodeAuthorised); + $this->assertNotSame($this->paymentResultCode, $paymentResultCodeAuthorised); + } + + /** @test */ + public function it_throws_an_invalid_argument_exception_when_result_code_is_unknown(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid result code: "test"'); + + PaymentResultCode::load('test'); + } + + /** @test */ + public function it_can_load_a_result_code(): void + { + $this->assertEquals( + PaymentResultCode::authorised(), + PaymentResultCode::load('Authorised') + ); + } + + /** @test */ + public function it_knows_when_a_result_code_exists(): void + { + $result = PaymentResultCode::exists(PaymentResultCode::cancelled()->resultCode()); + + $this->assertTrue($result); + } + + /** @test */ + public function it_knows_when_a_result_code_doesnt_exists(): void + { + $result = PaymentResultCode::exists('invalid-code-test'); + + $this->assertFalse($result); + } + + /** + * @dataProvider resultCodeProvider + * @test + */ + public function it_can_be_constructed_with_named_constructors(PaymentResultCode $resultCode, string $code): void + { + $this->assertEquals($code, $resultCode->resultCode()); + } + + public function resultCodeProvider(): \Generator + { + yield [PaymentResultCode::authorised(), 'Authorised']; + yield [PaymentResultCode::cancelled(), 'Cancelled']; + yield [PaymentResultCode::challengeShopper(), 'ChallengeShopper']; + yield [PaymentResultCode::error(), 'Error']; + yield [PaymentResultCode::invalid(), 'Invalid']; + yield [PaymentResultCode::identifyShopper(), 'IdentifyShopper']; + yield [PaymentResultCode::pending(), 'Pending']; + yield [PaymentResultCode::received(), 'Received']; + yield [PaymentResultCode::redirectShopper(), 'RedirectShopper']; + yield [PaymentResultCode::refused(), 'Refused']; + } +} diff --git a/tests/Unit/Models/PaymentResultCodesTest.php b/tests/Unit/Models/PaymentResultCodesTest.php deleted file mode 100644 index 0b857464..00000000 --- a/tests/Unit/Models/PaymentResultCodesTest.php +++ /dev/null @@ -1,90 +0,0 @@ -paymentResultCodes = PaymentResultCodes::authorised(); - } - - /** @test */ - public function it_knows_when_it_equals_payment_result_codes_objects(): void - { - $this->assertTrue($this->paymentResultCodes->equals(PaymentResultCodes::authorised())); - $this->assertFalse($this->paymentResultCodes->equals(PaymentResultCodes::invalid())); - } - - /** @test */ - public function it_is_immutable_constructed(): void - { - $paymentResultCodeAuthorised = PaymentResultCodes::authorised(); - $this->assertEquals($this->paymentResultCodes, $paymentResultCodeAuthorised); - $this->assertNotSame($this->paymentResultCodes, $paymentResultCodeAuthorised); - } - - /** @test */ - public function it_throws_an_invalid_argument_exception_when_result_code_is_unknown(): void - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid result code: "test"'); - - PaymentResultCodes::load('test'); - } - - /** @test */ - public function it_can_load_a_result_code(): void - { - $this->assertEquals( - PaymentResultCodes::authorised(), - PaymentResultCodes::load('Authorised') - ); - } - - /** @test */ - public function it_knows_when_a_result_code_exists(): void - { - $result = PaymentResultCodes::exists(PaymentResultCodes::cancelled()->resultCode()); - - $this->assertTrue($result); - } - - /** @test */ - public function it_knows_when_a_result_code_doesnt_exists(): void - { - $result = PaymentResultCodes::exists('invalid-code-test'); - - $this->assertFalse($result); - } - - /** - * @dataProvider resultCodeProvider - * @test - */ - public function it_can_be_constructed_with_named_constructors(PaymentResultCodes $resultCode, string $code): void - { - $this->assertEquals($code, $resultCode->resultCode()); - } - - public function resultCodeProvider(): \Generator - { - yield [PaymentResultCodes::authorised(), 'Authorised']; - yield [PaymentResultCodes::cancelled(), 'Cancelled']; - yield [PaymentResultCodes::challengeShopper(), 'ChallengeShopper']; - yield [PaymentResultCodes::error(), 'Error']; - yield [PaymentResultCodes::invalid(), 'Invalid']; - yield [PaymentResultCodes::identifyShopper(), 'IdentifyShopper']; - yield [PaymentResultCodes::pending(), 'Pending']; - yield [PaymentResultCodes::received(), 'Received']; - yield [PaymentResultCodes::redirectShopper(), 'RedirectShopper']; - yield [PaymentResultCodes::refused(), 'Refused']; - } -} diff --git a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php index fae0a792..20c7a5a0 100644 --- a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php +++ b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php @@ -4,7 +4,7 @@ namespace Unit\Models\RecurringPayment; -use AdyenPayment\Models\PaymentResultCodes; +use AdyenPayment\Models\PaymentResultCode; use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; use AdyenPayment\Models\TokenIdentifier; use PHPUnit\Framework\TestCase; @@ -22,7 +22,7 @@ protected function setUp(): void $recurringDetailReference = '8415698462516992', $pspReference = '8515815919501547', $orderNumber = 'YOUR_ORDER_NUMBER', - $resultCode = PaymentResultCodes::authorised(), + $resultCode = PaymentResultCode::authorised(), $amountValue = 10500, $amountCurrency = 'EUR' ); @@ -129,7 +129,7 @@ public function it_knows_when_it_is_a_subscription(): void '8415698462516992', '8515815919501547', $orderNumber = '', - PaymentResultCodes::authorised(), + PaymentResultCode::authorised(), 10500, 'EUR' ); diff --git a/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php b/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php new file mode 100644 index 00000000..2f847646 --- /dev/null +++ b/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php @@ -0,0 +1,192 @@ +entityManager = $this->prophesize(EntityManager::class); + $this->recurringPaymentTokenEntityRepository = $this->prophesize(EntityRepository::class); + $this->recurringPaymentTokenRepository = new RecurringPaymentTokenRepository( + $this->entityManager->reveal(), + $this->recurringPaymentTokenEntityRepository->reveal() + ); + } + + /** @test */ + public function it_is_a_recurring_payment_token_repository(): void + { + $this->assertInstanceOf( + RecurringPaymentTokenRepositoryInterface::class, + $this->recurringPaymentTokenRepository + ); + } + + /** @test */ + public function it_can_save_a_recurring_payment_token(): void + { + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $this->entityManager->persist($recurringPaymentToken->reveal())->shouldBeCalled(); + $this->entityManager->flush($recurringPaymentToken->reveal())->shouldBeCalled(); + + $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); + } + + /** @test */ + public function it_can_catch_a_orm_exception_on_saving_a_recurring_payment_token(): void + { + $ormException = new ORMException(); + $token = TokenIdentifier::generate(); + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $recurringPaymentToken->tokenIdentifier()->willReturn($token); + + $this->entityManager->persist($recurringPaymentToken->reveal())->willThrow($ormException); + $this->entityManager->flush(Argument::any())->shouldNotBeCalled(); + + self::expectException(RecurringPaymentTokenNotSavedException::class); + + $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); + } + + /** @test */ + public function it_can_catch_a_orm_invalid_argument_exception_on_saving_a_recurring_payment_token(): void + { + $ormException = new ORMInvalidArgumentException(); + $token = TokenIdentifier::generate(); + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $recurringPaymentToken->tokenIdentifier()->willReturn($token); + + $this->entityManager->persist($recurringPaymentToken->reveal())->willThrow($ormException); + $this->entityManager->flush(Argument::any())->shouldNotBeCalled(); + + self::expectException(RecurringPaymentTokenNotSavedException::class); + + $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); + } + + /** @test */ + public function it_can_fetch_a_recurring_payment_token_by_customer_id_and_order_number(): void + { + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + + $this->recurringPaymentTokenEntityRepository->findOneBy([ + 'customerId' => $customerId = 'customer-id', + 'orderNumber' => $orderNumber = 'order-number', + ])->willReturn($recurringPaymentToken->reveal()); + + $result = $this->recurringPaymentTokenRepository->fetchByCustomerIdAndOrderNumber($customerId, $orderNumber); + + self::assertEquals($recurringPaymentToken->reveal(), $result); + } + + /** @test */ + public function it_will_throw_an_error_on_missing_recurring_payment_token_by_customer_id_and_order_number(): void + { + $this->recurringPaymentTokenEntityRepository->findOneBy([ + 'customerId' => $customerId = 'customer-id', + 'orderNumber' => $orderNumber = 'order-number', + ])->willReturn(null); + + self::expectException(RecurringPaymentTokenNotFoundException::class); + + $this->recurringPaymentTokenRepository->fetchByCustomerIdAndOrderNumber($customerId, $orderNumber); + } + + /** @test */ + public function it_can_fetch_a_recurring_payment_token_by_psp_reference(): void + { + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + + $this->recurringPaymentTokenEntityRepository->findOneBy([ + 'resultCode' => PaymentResultCode::pending()->resultCode(), + 'pspReference' => $pspReference = 'psp-reference', + ])->willReturn($recurringPaymentToken->reveal()); + + $result = $this->recurringPaymentTokenRepository->fetchPendingByPspReference($pspReference); + + self::assertEquals($recurringPaymentToken->reveal(), $result); + } + + /** @test */ + public function it_will_throw_an_error_on_missing_recurring_payment_token_by_psp_reference(): void + { + $this->recurringPaymentTokenEntityRepository->findOneBy([ + 'resultCode' => PaymentResultCode::pending()->resultCode(), + 'pspReference' => $pspReference = 'psp-reference', + ])->willReturn(null); + + self::expectException(RecurringPaymentTokenNotFoundException::class); + + $this->recurringPaymentTokenRepository->fetchPendingByPspReference($pspReference); + } + + /** @test */ + public function it_can_update_a_recurring_payment_token(): void + { + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $this->entityManager->persist($recurringPaymentToken->reveal())->shouldBeCalled(); + $this->entityManager->flush($recurringPaymentToken->reveal())->shouldBeCalled(); + + $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); + } + + /** @test */ + public function it_can_catch_a_orm_exception_on_updating_a_recurring_payment_token(): void + { + $ormException = new ORMException(); + $token = TokenIdentifier::generate(); + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $recurringPaymentToken->tokenIdentifier()->willReturn($token); + + $this->entityManager->persist($recurringPaymentToken->reveal())->willThrow($ormException); + $this->entityManager->flush(Argument::any())->shouldNotBeCalled(); + + self::expectException(RecurringPaymentTokenNotSavedException::class); + + $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); + } + + /** @test */ + public function it_can_catch_a_orm_invalid_argument_exception_on_updating_a_recurring_payment_token(): void + { + $ormException = new ORMInvalidArgumentException(); + $token = TokenIdentifier::generate(); + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $recurringPaymentToken->tokenIdentifier()->willReturn($token); + + $this->entityManager->persist($recurringPaymentToken->reveal())->willThrow($ormException); + $this->entityManager->flush(Argument::any())->shouldNotBeCalled(); + + self::expectException(RecurringPaymentTokenNotSavedException::class); + + $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); + } +} From c490175d45a40b53bea3eeda9e28aef94fae5e48 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 24 Feb 2022 08:39:28 +0100 Subject: [PATCH 092/136] ASW-471 - CR fixes and tests --- .../RecurringPaymentTokenRepository.php | 21 +-- ...curringPaymentTokenRepositoryInterface.php | 1 - ...aceableRecurringPaymentTokenRepository.php | 12 +- Resources/services/repositories.xml | 3 - .../RecurringPaymentTokenRepositoryTest.php | 86 +--------- ...bleRecurringPaymentTokenRepositoryTest.php | 151 ++++++++++++++++++ 6 files changed, 158 insertions(+), 116 deletions(-) create mode 100644 tests/Unit/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepositoryTest.php diff --git a/Repository/RecurringPayment/RecurringPaymentTokenRepository.php b/Repository/RecurringPayment/RecurringPaymentTokenRepository.php index 9b1fc84c..f405a853 100644 --- a/Repository/RecurringPayment/RecurringPaymentTokenRepository.php +++ b/Repository/RecurringPayment/RecurringPaymentTokenRepository.php @@ -5,13 +5,10 @@ namespace AdyenPayment\Repository\RecurringPayment; use AdyenPayment\Exceptions\RecurringPaymentTokenNotFoundException; -use AdyenPayment\Exceptions\RecurringPaymentTokenNotSavedException; use AdyenPayment\Models\PaymentResultCode; use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityRepository; -use Doctrine\ORM\ORMException; -use Doctrine\ORM\ORMInvalidArgumentException; final class RecurringPaymentTokenRepository implements RecurringPaymentTokenRepositoryInterface { @@ -24,16 +21,6 @@ public function __construct(EntityManager $entityManager, EntityRepository $recu $this->recurringPaymentTokenEntityRepository = $recurringPaymentTokenEntityRepository; } - public function save(RecurringPaymentToken $recurringPaymentToken): void - { - try { - $this->entityManager->persist($recurringPaymentToken); - $this->entityManager->flush($recurringPaymentToken); - } catch (ORMException|ORMInvalidArgumentException $exception) { - throw RecurringPaymentTokenNotSavedException::withId($recurringPaymentToken->tokenIdentifier()); - } - } - public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orderNumber): RecurringPaymentToken { $recurringPaymentToken = $this->recurringPaymentTokenEntityRepository->findOneBy([ @@ -64,11 +51,7 @@ public function fetchPendingByPspReference(string $pspReference): RecurringPayme public function update(RecurringPaymentToken $recurringPaymentToken): void { - try { - $this->entityManager->persist($recurringPaymentToken); - $this->entityManager->flush($recurringPaymentToken); - } catch (ORMException|ORMInvalidArgumentException $exception) { - throw RecurringPaymentTokenNotSavedException::withId($recurringPaymentToken->tokenIdentifier()); - } + $this->entityManager->persist($recurringPaymentToken); + $this->entityManager->flush($recurringPaymentToken); } } diff --git a/Repository/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php b/Repository/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php index b4f75cf8..0eb07313 100644 --- a/Repository/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php +++ b/Repository/RecurringPayment/RecurringPaymentTokenRepositoryInterface.php @@ -8,7 +8,6 @@ interface RecurringPaymentTokenRepositoryInterface { - public function save(RecurringPaymentToken $recurringPaymentToken): void; public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orderNumber): RecurringPaymentToken; public function fetchPendingByPspReference(string $pspReference): RecurringPaymentToken; public function update(RecurringPaymentToken $recurringPaymentToken): void; diff --git a/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepository.php b/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepository.php index ad94a1e4..797b5133 100644 --- a/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepository.php +++ b/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepository.php @@ -5,6 +5,7 @@ namespace AdyenPayment\Repository\RecurringPayment; use AdyenPayment\Exceptions\RecurringPaymentTokenNotFoundException; +use AdyenPayment\Exceptions\RecurringPaymentTokenNotSavedException; use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMInvalidArgumentException; @@ -23,15 +24,6 @@ public function __construct( $this->logger = $logger; } - public function save(RecurringPaymentToken $recurringPaymentToken): void - { - try { - $this->recurringPaymentTokenRepository->save($recurringPaymentToken); - } catch (ORMException|ORMInvalidArgumentException $exception) { - $this->logger->error($exception->getMessage(), ['exception' => $exception]); - } - } - public function fetchByCustomerIdAndOrderNumber(string $customerId, string $orderNumber): RecurringPaymentToken { try { @@ -60,6 +52,8 @@ public function update(RecurringPaymentToken $recurringPaymentToken): void $this->recurringPaymentTokenRepository->update($recurringPaymentToken); } catch (ORMException|ORMInvalidArgumentException $exception) { $this->logger->error($exception->getMessage(), ['exception' => $exception]); + + throw RecurringPaymentTokenNotSavedException::withId($recurringPaymentToken->tokenIdentifier()); } } } diff --git a/Resources/services/repositories.xml b/Resources/services/repositories.xml index 27766034..aae2f781 100644 --- a/Resources/services/repositories.xml +++ b/Resources/services/repositories.xml @@ -25,6 +25,3 @@ - - - diff --git a/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php b/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php index 2f847646..4a80b51d 100644 --- a/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php +++ b/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php @@ -5,18 +5,13 @@ namespace AdyenPayment\Tests\Unit\Repository\RecurringPayment; use AdyenPayment\Exceptions\RecurringPaymentTokenNotFoundException; -use AdyenPayment\Exceptions\RecurringPaymentTokenNotSavedException; use AdyenPayment\Models\PaymentResultCode; use AdyenPayment\Models\RecurringPayment\RecurringPaymentToken; -use AdyenPayment\Models\TokenIdentifier; use AdyenPayment\Repository\RecurringPayment\RecurringPaymentTokenRepository; use AdyenPayment\Repository\RecurringPayment\RecurringPaymentTokenRepositoryInterface; use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityRepository; -use Doctrine\ORM\ORMException; -use Doctrine\ORM\ORMInvalidArgumentException; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; @@ -44,52 +39,7 @@ protected function setUp(): void /** @test */ public function it_is_a_recurring_payment_token_repository(): void { - $this->assertInstanceOf( - RecurringPaymentTokenRepositoryInterface::class, - $this->recurringPaymentTokenRepository - ); - } - - /** @test */ - public function it_can_save_a_recurring_payment_token(): void - { - $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); - $this->entityManager->persist($recurringPaymentToken->reveal())->shouldBeCalled(); - $this->entityManager->flush($recurringPaymentToken->reveal())->shouldBeCalled(); - - $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); - } - - /** @test */ - public function it_can_catch_a_orm_exception_on_saving_a_recurring_payment_token(): void - { - $ormException = new ORMException(); - $token = TokenIdentifier::generate(); - $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); - $recurringPaymentToken->tokenIdentifier()->willReturn($token); - - $this->entityManager->persist($recurringPaymentToken->reveal())->willThrow($ormException); - $this->entityManager->flush(Argument::any())->shouldNotBeCalled(); - - self::expectException(RecurringPaymentTokenNotSavedException::class); - - $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); - } - - /** @test */ - public function it_can_catch_a_orm_invalid_argument_exception_on_saving_a_recurring_payment_token(): void - { - $ormException = new ORMInvalidArgumentException(); - $token = TokenIdentifier::generate(); - $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); - $recurringPaymentToken->tokenIdentifier()->willReturn($token); - - $this->entityManager->persist($recurringPaymentToken->reveal())->willThrow($ormException); - $this->entityManager->flush(Argument::any())->shouldNotBeCalled(); - - self::expectException(RecurringPaymentTokenNotSavedException::class); - - $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); + $this->assertInstanceOf(RecurringPaymentTokenRepositoryInterface::class, $this->recurringPaymentTokenRepository); } /** @test */ @@ -155,38 +105,6 @@ public function it_can_update_a_recurring_payment_token(): void $this->entityManager->persist($recurringPaymentToken->reveal())->shouldBeCalled(); $this->entityManager->flush($recurringPaymentToken->reveal())->shouldBeCalled(); - $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); - } - - /** @test */ - public function it_can_catch_a_orm_exception_on_updating_a_recurring_payment_token(): void - { - $ormException = new ORMException(); - $token = TokenIdentifier::generate(); - $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); - $recurringPaymentToken->tokenIdentifier()->willReturn($token); - - $this->entityManager->persist($recurringPaymentToken->reveal())->willThrow($ormException); - $this->entityManager->flush(Argument::any())->shouldNotBeCalled(); - - self::expectException(RecurringPaymentTokenNotSavedException::class); - - $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); - } - - /** @test */ - public function it_can_catch_a_orm_invalid_argument_exception_on_updating_a_recurring_payment_token(): void - { - $ormException = new ORMInvalidArgumentException(); - $token = TokenIdentifier::generate(); - $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); - $recurringPaymentToken->tokenIdentifier()->willReturn($token); - - $this->entityManager->persist($recurringPaymentToken->reveal())->willThrow($ormException); - $this->entityManager->flush(Argument::any())->shouldNotBeCalled(); - - self::expectException(RecurringPaymentTokenNotSavedException::class); - - $this->recurringPaymentTokenRepository->save($recurringPaymentToken->reveal()); + $this->recurringPaymentTokenRepository->update($recurringPaymentToken->reveal()); } } diff --git a/tests/Unit/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepositoryTest.php b/tests/Unit/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepositoryTest.php new file mode 100644 index 00000000..cfdc7fd1 --- /dev/null +++ b/tests/Unit/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepositoryTest.php @@ -0,0 +1,151 @@ +recurringPaymentTokenRepository = $this->prophesize(RecurringPaymentTokenRepositoryInterface::class); + $this->logger = $this->prophesize(LoggerInterface::class); + $this->traceableRecurringPaymentTokenRepository = new TraceableRecurringPaymentTokenRepository( + $this->recurringPaymentTokenRepository->reveal(), + $this->logger->reveal() + ); + } + + /** @test */ + public function it_is_a_recurring_payment_token_repository(): void + { + $this->assertInstanceOf( + RecurringPaymentTokenRepositoryInterface::class, + $this->traceableRecurringPaymentTokenRepository + ); + } + + /** @test */ + public function it_can_fetch_a_recurring_payment_token_by_customer_id_and_order_number(): void + { + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + + $this->recurringPaymentTokenRepository->fetchByCustomerIdAndOrderNumber( + $customerId = 'customer-id', + $orderNumber = 'order-number' + )->willReturn($recurringPaymentToken->reveal()); + + $result = $this->traceableRecurringPaymentTokenRepository->fetchByCustomerIdAndOrderNumber( + $customerId, + $orderNumber + ); + + self::assertEquals($recurringPaymentToken->reveal(), $result); + } + + /** @test */ + public function it_will_throw_an_error_on_missing_recurring_payment_token_by_customer_id_and_order_number(): void + { + $exception = new RecurringPaymentTokenNotFoundException(); + $this->recurringPaymentTokenRepository->fetchByCustomerIdAndOrderNumber( + $customerId = 'customer-id', + $orderNumber = 'order-number' + )->willThrow($exception); + + $this->logger->info($exception->getMessage(), ['exception' => $exception])->shouldBeCalled(); + + self::expectException(RecurringPaymentTokenNotFoundException::class); + + $this->traceableRecurringPaymentTokenRepository->fetchByCustomerIdAndOrderNumber($customerId, $orderNumber); + } + + /** @test */ + public function it_can_fetch_a_recurring_payment_token_by_psp_reference(): void + { + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + + $this->recurringPaymentTokenRepository->fetchPendingByPspReference($pspReference = 'psp-reference') + ->willReturn($recurringPaymentToken->reveal()); + + $result = $this->traceableRecurringPaymentTokenRepository->fetchPendingByPspReference($pspReference); + + self::assertEquals($recurringPaymentToken->reveal(), $result); + } + + /** @test */ + public function it_will_throw_an_error_on_missing_recurring_payment_token_by_psp_reference(): void + { + $exception = new RecurringPaymentTokenNotFoundException(); + $this->recurringPaymentTokenRepository->fetchPendingByPspReference($pspReference = 'psp-reference') + ->willThrow($exception); + + $this->logger->info($exception->getMessage(), ['exception' => $exception])->shouldBeCalled(); + + self::expectException(RecurringPaymentTokenNotFoundException::class); + + $this->traceableRecurringPaymentTokenRepository->fetchPendingByPspReference($pspReference); + } + + /** @test */ + public function it_can_update_a_recurring_payment_token(): void + { + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $this->recurringPaymentTokenRepository->update($recurringPaymentToken->reveal())->shouldBeCalled(); + + $this->traceableRecurringPaymentTokenRepository->update($recurringPaymentToken->reveal()); + } + + /** @test */ + public function it_can_catch_a_orm_exception_on_updating_a_recurring_payment_token(): void + { + $ormException = new ORMException(); + $token = TokenIdentifier::generate(); + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $recurringPaymentToken->tokenIdentifier()->willReturn($token); + + $this->recurringPaymentTokenRepository->update($recurringPaymentToken->reveal())->willThrow($ormException); + $this->logger->error($ormException->getMessage(), ['exception' => $ormException]); + + self::expectException(RecurringPaymentTokenNotSavedException::class); + + $this->traceableRecurringPaymentTokenRepository->update($recurringPaymentToken->reveal()); + } + + /** @test */ + public function it_can_catch_a_orm_invalid_argument_exception_on_updating_a_recurring_payment_token(): void + { + $ormException = new ORMInvalidArgumentException(); + $token = TokenIdentifier::generate(); + $recurringPaymentToken = $this->prophesize(RecurringPaymentToken::class); + $recurringPaymentToken->tokenIdentifier()->willReturn($token); + + $this->recurringPaymentTokenRepository->update($recurringPaymentToken->reveal())->willThrow($ormException); + $this->logger->error($ormException->getMessage(), ['exception' => $ormException]); + + self::expectException(RecurringPaymentTokenNotSavedException::class); + + $this->traceableRecurringPaymentTokenRepository->update($recurringPaymentToken->reveal()); + } +} From 2bb3954629c184cef7425ecbf2aff4f91f5c83df Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 28 Feb 2022 07:41:41 +0100 Subject: [PATCH 093/136] ASW-471 - CR fixes --- ...rringPaymentTokenNotFoundExceptionTest.php | 19 +++++++++++++++---- ...rringPaymentTokenNotSavedExceptionTest.php | 16 ++++++++++++++-- .../RecurringPaymentTokenRepositoryTest.php | 1 + ...bleRecurringPaymentTokenRepositoryTest.php | 1 + 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php b/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php index 0df12408..1d1770fc 100644 --- a/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php +++ b/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php @@ -10,15 +10,27 @@ final class RecurringPaymentTokenNotFoundExceptionTest extends TestCase { + private RecurringPaymentTokenNotFoundException $exception; + + protected function setUp(): void + { + $this->exception = new RecurringPaymentTokenNotFoundException(); + } + + /** @test */ + public function is_a_runtime_exception(): void + { + self::assertInstanceOf(\RuntimeException::class, $this->exception); + } + /** @test */ - public function it_can_return_an_exception_with_customer_id_and_order_number(): void + public function it_can_be_constructed_with_customer_id_and_order_number(): void { $exception = RecurringPaymentTokenNotFoundException::withCustomerIdAndOrderNumber( $customerId = 'customer-id', $orderNumber = 'order-number' ); - self::assertInstanceOf(\RuntimeException::class, $exception); self::assertInstanceOf(RecurringPaymentTokenNotFoundException::class, $exception); self::assertEquals( sprintf( @@ -31,13 +43,12 @@ public function it_can_return_an_exception_with_customer_id_and_order_number(): } /** @test */ - public function it_can_return_an_exception_with_psp_reference(): void + public function it_can_be_constructed_with_psp_reference(): void { $exception = RecurringPaymentTokenNotFoundException::withPendingResultCodeAndPspReference( $pspReference = 'psp-reference' ); - self::assertInstanceOf(\RuntimeException::class, $exception); self::assertInstanceOf(RecurringPaymentTokenNotFoundException::class, $exception); self::assertEquals( sprintf( diff --git a/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php b/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php index d7ac2582..9d0a30ae 100644 --- a/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php +++ b/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php @@ -10,14 +10,26 @@ final class RecurringPaymentTokenNotSavedExceptionTest extends TestCase { + private RecurringPaymentTokenNotSavedException $exception; + + protected function setUp(): void + { + $this->exception = new RecurringPaymentTokenNotSavedException(); + } + + /** @test */ + public function is_a_runtime_exception(): void + { + self::assertInstanceOf(\RuntimeException::class, $this->exception); + } + /** @test */ - public function it_can_return_an_exception_with_customer_id_and_order_number(): void + public function it_can_be_constructed_with_token_identifier(): void { $tokenIdentifier = TokenIdentifier::generate(); $exception = RecurringPaymentTokenNotSavedException::withId($tokenIdentifier); - self::assertInstanceOf(\RuntimeException::class, $exception); self::assertInstanceOf(RecurringPaymentTokenNotSavedException::class, $exception); self::assertEquals( 'Recurring payment token not saved with id:'.$tokenIdentifier->identifier(), diff --git a/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php b/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php index 4a80b51d..a8a91d30 100644 --- a/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php +++ b/tests/Unit/Repository/RecurringPayment/RecurringPaymentTokenRepositoryTest.php @@ -15,6 +15,7 @@ use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; +// @TODO: refactor to integration test. final class RecurringPaymentTokenRepositoryTest extends TestCase { use ProphecyTrait; diff --git a/tests/Unit/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepositoryTest.php b/tests/Unit/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepositoryTest.php index cfdc7fd1..95217042 100644 --- a/tests/Unit/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepositoryTest.php +++ b/tests/Unit/Repository/RecurringPayment/TraceableRecurringPaymentTokenRepositoryTest.php @@ -17,6 +17,7 @@ use Prophecy\Prophecy\ObjectProphecy; use Psr\Log\LoggerInterface; +// @TODO: refactor to integration test. final class TraceableRecurringPaymentTokenRepositoryTest extends TestCase { use ProphecyTrait; From a8c9703690cc199c946ae3592b9d6c5fe7d1e904 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 28 Feb 2022 10:08:32 +0100 Subject: [PATCH 094/136] ASW-477 - CR comment --- Components/Adyen/PaymentMethodService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/Adyen/PaymentMethodService.php b/Components/Adyen/PaymentMethodService.php index 0c041973..6873d107 100644 --- a/Components/Adyen/PaymentMethodService.php +++ b/Components/Adyen/PaymentMethodService.php @@ -13,9 +13,9 @@ 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 { - /** @todo cleanup the public const (unify the services) */ public const IMPORT_LOCALE = 'en_GB'; private ApiClientMap $apiClientMap; private Configuration $configuration; From 8fffd35518d1328e112419a0a176a144a3800c5b Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Tue, 22 Feb 2022 12:03:17 +0100 Subject: [PATCH 095/136] ASW-470 - CR fixes --- .../RecurringPaymentToken.php | 5 ++-- .../RecurringPaymentTokenTest.php | 4 +-- tests/Unit/Models/TokenIdentifierTest.php | 28 +++++++++---------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Models/RecurringPayment/RecurringPaymentToken.php b/Models/RecurringPayment/RecurringPaymentToken.php index e66dcb1e..61dbd8e0 100644 --- a/Models/RecurringPayment/RecurringPaymentToken.php +++ b/Models/RecurringPayment/RecurringPaymentToken.php @@ -22,7 +22,6 @@ class RecurringPaymentToken extends ModelEntity /** * @ORM\Column(name="id", type="string", nullable=false) * @ORM\Id - * @ORM\GeneratedValue(strategy="NONE") */ private string $id; @@ -113,7 +112,9 @@ public function id(): string public function tokenIdentifier(): TokenIdentifier { - return $this->tokenIdentifier = TokenIdentifier::generateFromString($this->id); + $this->tokenIdentifier = TokenIdentifier::generateFromString($this->id); + + return $this->tokenIdentifier; } public function customerId(): string diff --git a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php index 20c7a5a0..b0a9b0e9 100644 --- a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php +++ b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php @@ -98,8 +98,8 @@ public function it_contains_a_created_at_timestamp(): void $this->recurringPaymentToken->setCreatedAt($createdAt); $this->assertInstanceOf(\DateTimeImmutable::class, $this->recurringPaymentToken->createdAt()); $this->assertStringContainsString( - $createdAt->format('d/m/y'), - $this->recurringPaymentToken->createdAt()->format('d/m/y') + $createdAt->format('d/m/y H:i'), + $this->recurringPaymentToken->createdAt()->format('d/m/y H:i') ); } diff --git a/tests/Unit/Models/TokenIdentifierTest.php b/tests/Unit/Models/TokenIdentifierTest.php index 544a5402..122388ba 100644 --- a/tests/Unit/Models/TokenIdentifierTest.php +++ b/tests/Unit/Models/TokenIdentifierTest.php @@ -10,11 +10,10 @@ class TokenIdentifierTest extends TestCase { private TokenIdentifier $tokenIdentifier; - private string $knownUuid = '3a2ee0d3-adc0-4386-869d-429b6d5f1fa0'; protected function setUp(): void { - $this->tokenIdentifier = TokenIdentifier::generateFromString($this->knownUuid); + $this->tokenIdentifier = TokenIdentifier::generateFromString('3a2ee0d3-adc0-4386-869d-429b6d5f1fa0'); } /** @test */ @@ -24,32 +23,33 @@ public function it_contains_a_token_identifier(): void } /** @test */ - public function it_can_compare_token_identifier_objects(): void + public function it_knows_when_it_equals_token_identifier_objects(): void { - $this->assertTrue($this->tokenIdentifier->equals(TokenIdentifier::generateFromString($this->knownUuid))); + $this->assertTrue($this->tokenIdentifier->equals(TokenIdentifier::generateFromString('3a2ee0d3-adc0-4386-869d-429b6d5f1fa0'))); $this->assertFalse($this->tokenIdentifier->equals(TokenIdentifier::generate())); } /** @test */ - public function it_checks_token_identifier_on_immutabillity(): void + public function it_constructs_immutable(): void { - $tokenIdentifier = TokenIdentifier::generateFromString($this->knownUuid); + $tokenIdentifier = TokenIdentifier::generateFromString('3a2ee0d3-adc0-4386-869d-429b6d5f1fa0'); $this->assertEquals($this->tokenIdentifier, $tokenIdentifier); $this->assertNotSame($this->tokenIdentifier, $tokenIdentifier); } - /** - * @dataProvider tokenIdentifierProvider - * @test - */ - public function it_can_be_constructed_with_named_constructors(TokenIdentifier $tokenIdentifier, string $expected): void + /** @test */ + public function it_can_be_constructed_from_string(): void { + $tokenIdentifier = TokenIdentifier::generateFromString($expected = 'af55ecab-90db-4501-ba7d-9eef61ac3ee3'); + $this->assertEquals($expected, $tokenIdentifier->identifier()); } - public function tokenIdentifierProvider(): \Generator + /** @test */ + public function it_can_be_constructed_with_named_constructor(): void { - yield [TokenIdentifier::generateFromString('af55ecab-90db-4501-ba7d-9eef61ac3ee3'), 'af55ecab-90db-4501-ba7d-9eef61ac3ee3']; - yield [$randomGenerated = TokenIdentifier::generate(), $randomGenerated->identifier()]; + $tokenIdentifier = TokenIdentifier::generate(); + + $this->assertInstanceOf(TokenIdentifier::class, $tokenIdentifier); } } From b96f442d590e3076d84b359240b33f32683d1345 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 28 Feb 2022 10:51:27 +0100 Subject: [PATCH 096/136] ASW-470 - CR fixes --- .../RecurringPaymentToken.php | 27 ++++++++++++------- .../RecurringPaymentTokenTest.php | 8 +++++- .../Mapper/RecurringTokenMapperTest.php | 5 ++-- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Models/RecurringPayment/RecurringPaymentToken.php b/Models/RecurringPayment/RecurringPaymentToken.php index 61dbd8e0..ea45d5b4 100644 --- a/Models/RecurringPayment/RecurringPaymentToken.php +++ b/Models/RecurringPayment/RecurringPaymentToken.php @@ -25,11 +25,6 @@ class RecurringPaymentToken extends ModelEntity */ private string $id; - /** - * @ORM\Column(name="token_identifier", type="string", nullable=false) - */ - private TokenIdentifier $tokenIdentifier; - /** * @ORM\Column(name="customer_id", type="string", length=255, nullable=false) */ @@ -93,7 +88,6 @@ public static function create( ): self { $new = new self(); $new->id = $id->identifier(); - $new->tokenIdentifier = $id; $new->customerId = $customerId; $new->recurringDetailReference = $recurringDetailReference; $new->pspReference = $pspReference; @@ -105,6 +99,11 @@ public static function create( return $new; } + /** + * @internal + * + * @see RecurringPaymentToken::tokenIdentifier() + */ public function id(): string { return $this->id; @@ -112,9 +111,7 @@ public function id(): string public function tokenIdentifier(): TokenIdentifier { - $this->tokenIdentifier = TokenIdentifier::generateFromString($this->id); - - return $this->tokenIdentifier; + return TokenIdentifier::generateFromString($this->id); } public function customerId(): string @@ -137,11 +134,21 @@ public function orderNumber(): string return $this->orderNumber; } - public function resultCode(): string + /** + * @internal + * + * @see RecurringPaymentToken::resultCode() + */ + public function getResultCode(): string { return $this->resultCode; } + public function resultCode(): PaymentResultCode + { + return PaymentResultCode::load($this->resultCode); + } + public function amountValue(): int { return $this->amountValue; diff --git a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php index b0a9b0e9..325a9785 100644 --- a/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php +++ b/tests/Unit/Models/RecurringPayment/RecurringPaymentTokenTest.php @@ -73,10 +73,16 @@ public function it_contains_an_order_number(): void $this->assertEquals('YOUR_ORDER_NUMBER', $this->recurringPaymentToken->orderNumber()); } + /** @test */ + public function it_contains_a_result_code_string(): void + { + $this->assertEquals('Authorised', $this->recurringPaymentToken->getResultCode()); + } + /** @test */ public function it_contains_a_result_code(): void { - $this->assertEquals('Authorised', $this->recurringPaymentToken->resultCode()); + $this->assertEquals(PaymentResultCode::load('Authorised'), $this->recurringPaymentToken->resultCode()); } /** @test */ diff --git a/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php b/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php index 057e34fc..4a72fbdd 100644 --- a/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php +++ b/tests/Unit/Recurring/Mapper/RecurringTokenMapperTest.php @@ -5,6 +5,7 @@ namespace Unit\Recurring\Mapper; use AdyenPayment\Exceptions\InvalidPaymentsResponseException; +use AdyenPayment\Models\PaymentResultCode; use AdyenPayment\Recurring\Mapper\RecurringTokenMapper; use AdyenPayment\Recurring\Mapper\RecurringTokenMapperInterface; use PHPUnit\Framework\TestCase; @@ -60,7 +61,7 @@ public function it_can_map_from_array(): void $this->assertEquals('8415698462516992', $recurringPaymentToken->recurringDetailReference()); $this->assertEquals('8515815919501547', $recurringPaymentToken->pspReference()); $this->assertEquals('YOUR_ORDER_NUMBER', $recurringPaymentToken->orderNumber()); - $this->assertEquals('Authorised', $recurringPaymentToken->resultCode()); + $this->assertEquals(PaymentResultCode::load('Authorised'), $recurringPaymentToken->resultCode()); $this->assertIsInt($recurringPaymentToken->amountValue()); $this->assertEquals(0, $recurringPaymentToken->amountValue()); $this->assertEquals('USD', $recurringPaymentToken->amountCurrency()); @@ -81,7 +82,7 @@ public function it_can_map_default_values(): void $this->assertEquals('', $recurringPaymentToken->recurringDetailReference()); $this->assertEquals('', $recurringPaymentToken->pspReference()); $this->assertEquals('', $recurringPaymentToken->orderNumber()); - $this->assertEquals('Invalid', $recurringPaymentToken->resultCode()); + $this->assertEquals(PaymentResultCode::load('Invalid'), $recurringPaymentToken->resultCode()); $this->assertEquals(0, $recurringPaymentToken->amountValue()); $this->assertEquals('', $recurringPaymentToken->amountCurrency()); } From d1fb4788e630a704b415fe6f92d8190378e4b5ee Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 28 Feb 2022 11:32:03 +0100 Subject: [PATCH 097/136] ASW-474 - Recurring one off payment token provider --- .../RecurringOneOffPaymentTokenProvider.php | 27 +++++++++ .../Providers/RecurringPaymentProvider.php | 3 +- Resources/services/components.xml | 28 ---------- Resources/services/payload-providers.xml | 56 +++++++++++++++++++ 4 files changed, 85 insertions(+), 29 deletions(-) create mode 100644 Components/Payload/Providers/RecurringOneOffPaymentTokenProvider.php create mode 100644 Resources/services/payload-providers.xml diff --git a/Components/Payload/Providers/RecurringOneOffPaymentTokenProvider.php b/Components/Payload/Providers/RecurringOneOffPaymentTokenProvider.php new file mode 100644 index 00000000..d106da75 --- /dev/null +++ b/Components/Payload/Providers/RecurringOneOffPaymentTokenProvider.php @@ -0,0 +1,27 @@ +getPaymentInfo(); + $storedPaymentMethodId = $paymentInfo['storedPaymentMethodId'] ?? null; + if (!$storedPaymentMethodId) { + return []; + } + + return [ + 'shopperInteraction' => ShopperInteraction::ecommerce()->shopperInteraction(), + 'recurringProcessingModel' => RecurringProcessingModel::cardOnFile()->recurringProcessingModel(), + ]; + } +} diff --git a/Components/Payload/Providers/RecurringPaymentProvider.php b/Components/Payload/Providers/RecurringPaymentProvider.php index b1c742e2..8351026b 100644 --- a/Components/Payload/Providers/RecurringPaymentProvider.php +++ b/Components/Payload/Providers/RecurringPaymentProvider.php @@ -7,7 +7,8 @@ use AdyenPayment\Components\Payload\PaymentContext; use AdyenPayment\Components\Payload\PaymentPayloadProvider; -class RecurringPaymentProvider implements PaymentPayloadProvider +/** @TODO - Pending unit tests */ +final class RecurringPaymentProvider implements PaymentPayloadProvider { public function provide(PaymentContext $context): array { diff --git a/Resources/services/components.xml b/Resources/services/components.xml index adfb0f55..2bcccb21 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -59,34 +59,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Resources/services/payload-providers.xml b/Resources/services/payload-providers.xml new file mode 100644 index 00000000..e6ed8bbe --- /dev/null +++ b/Resources/services/payload-providers.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 19435129730b96759c359714548775a88b23e105 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 28 Feb 2022 11:45:44 +0100 Subject: [PATCH 098/136] ASW-474 - Validation changes --- .../Payload/Providers/RecurringOneOffPaymentTokenProvider.php | 4 ++-- Components/Payload/Providers/RecurringPaymentProvider.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Components/Payload/Providers/RecurringOneOffPaymentTokenProvider.php b/Components/Payload/Providers/RecurringOneOffPaymentTokenProvider.php index d106da75..2f4268ad 100644 --- a/Components/Payload/Providers/RecurringOneOffPaymentTokenProvider.php +++ b/Components/Payload/Providers/RecurringOneOffPaymentTokenProvider.php @@ -14,8 +14,8 @@ final class RecurringOneOffPaymentTokenProvider implements PaymentPayloadProvide public function provide(PaymentContext $context): array { $paymentInfo = $context->getPaymentInfo(); - $storedPaymentMethodId = $paymentInfo['storedPaymentMethodId'] ?? null; - if (!$storedPaymentMethodId) { + $storedPaymentMethodId = (string) ($paymentInfo['storedPaymentMethodId'] ?? ''); + if ('' === $storedPaymentMethodId) { return []; } diff --git a/Components/Payload/Providers/RecurringPaymentProvider.php b/Components/Payload/Providers/RecurringPaymentProvider.php index 8351026b..96a5a4f8 100644 --- a/Components/Payload/Providers/RecurringPaymentProvider.php +++ b/Components/Payload/Providers/RecurringPaymentProvider.php @@ -13,8 +13,8 @@ final class RecurringPaymentProvider implements PaymentPayloadProvider public function provide(PaymentContext $context): array { $paymentInfo = $context->getPaymentInfo(); - $storedPaymentMethodId = $paymentInfo['storedPaymentMethodId'] ?? null; - if (!$storedPaymentMethodId) { + $storedPaymentMethodId = (string) ($paymentInfo['storedPaymentMethodId'] ?? ''); + if ('' === $storedPaymentMethodId) { return []; } From c654e3102678702536dfda0d6c5f5a7a8348c7f6 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 28 Feb 2022 12:09:07 +0100 Subject: [PATCH 099/136] ASW-474 - Changes and unit tests --- .../Providers/RecurringPaymentProvider.php | 7 ++- ...ecurringOneOffPaymentTokenProviderTest.php | 58 +++++++++++++++++++ .../RecurringPaymentProviderTest.php | 58 +++++++++++++++++++ 3 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 tests/Unit/Components/Payload/Providers/RecurringOneOffPaymentTokenProviderTest.php create mode 100644 tests/Unit/Components/Payload/Providers/RecurringPaymentProviderTest.php diff --git a/Components/Payload/Providers/RecurringPaymentProvider.php b/Components/Payload/Providers/RecurringPaymentProvider.php index 96a5a4f8..bea7d3d3 100644 --- a/Components/Payload/Providers/RecurringPaymentProvider.php +++ b/Components/Payload/Providers/RecurringPaymentProvider.php @@ -6,8 +6,9 @@ use AdyenPayment\Components\Payload\PaymentContext; use AdyenPayment\Components\Payload\PaymentPayloadProvider; +use AdyenPayment\Models\RecurringPayment\RecurringProcessingModel; +use AdyenPayment\Models\RecurringPayment\ShopperInteraction; -/** @TODO - Pending unit tests */ final class RecurringPaymentProvider implements PaymentPayloadProvider { public function provide(PaymentContext $context): array @@ -19,8 +20,8 @@ public function provide(PaymentContext $context): array } return [ - 'shopperInteraction' => 'ContAuth', - 'recurringProcessingModel' => 'CardOnFile', + 'shopperInteraction' => ShopperInteraction::contAuth()->shopperInteraction(), + 'recurringProcessingModel' => RecurringProcessingModel::cardOnFile()->recurringProcessingModel(), ]; } } diff --git a/tests/Unit/Components/Payload/Providers/RecurringOneOffPaymentTokenProviderTest.php b/tests/Unit/Components/Payload/Providers/RecurringOneOffPaymentTokenProviderTest.php new file mode 100644 index 00000000..ceb4d73e --- /dev/null +++ b/tests/Unit/Components/Payload/Providers/RecurringOneOffPaymentTokenProviderTest.php @@ -0,0 +1,58 @@ +recurringOneOffPaymentTokenProvider = new RecurringOneOffPaymentTokenProvider(); + $this->paymentContext = $this->prophesize(PaymentContext::class); + } + + /** @test */ + public function it_is_a_recurring_payment_payload_provider(): void + { + self::assertInstanceOf(PaymentPayloadProvider::class, $this->recurringOneOffPaymentTokenProvider); + } + + /** @test */ + public function it_will_return_empty_for_none_stored_payment_method(): void + { + $this->paymentContext->getPaymentInfo()->willReturn([]); + + $result = $this->recurringOneOffPaymentTokenProvider->provide($this->paymentContext->reveal()); + + self::assertEquals([], $result); + } + + /** @test */ + public function it_can_return_the_recurring_one_off_payment_token_data(): void + { + $this->paymentContext->getPaymentInfo()->willReturn(['storedPaymentMethodId' => 'stored-method-id']); + + $result = $this->recurringOneOffPaymentTokenProvider->provide($this->paymentContext->reveal()); + + self::assertEquals([ + 'shopperInteraction' => ShopperInteraction::ecommerce()->shopperInteraction(), + 'recurringProcessingModel' => RecurringProcessingModel::cardOnFile()->recurringProcessingModel(), + ], $result); + } +} diff --git a/tests/Unit/Components/Payload/Providers/RecurringPaymentProviderTest.php b/tests/Unit/Components/Payload/Providers/RecurringPaymentProviderTest.php new file mode 100644 index 00000000..197e2f7a --- /dev/null +++ b/tests/Unit/Components/Payload/Providers/RecurringPaymentProviderTest.php @@ -0,0 +1,58 @@ +recurringPaymentProvider = new RecurringPaymentProvider(); + $this->paymentContext = $this->prophesize(PaymentContext::class); + } + + /** @test */ + public function it_is_a_recurring_payment_payload_provider(): void + { + self::assertInstanceOf(PaymentPayloadProvider::class, $this->recurringPaymentProvider); + } + + /** @test */ + public function it_will_return_empty_for_none_stored_payment_method(): void + { + $this->paymentContext->getPaymentInfo()->willReturn([]); + + $result = $this->recurringPaymentProvider->provide($this->paymentContext->reveal()); + + self::assertEquals([], $result); + } + + /** @test */ + public function it_can_return_the_recurring_one_off_payment_token_data(): void + { + $this->paymentContext->getPaymentInfo()->willReturn(['storedPaymentMethodId' => 'stored-method-id']); + + $result = $this->recurringPaymentProvider->provide($this->paymentContext->reveal()); + + self::assertEquals([ + 'shopperInteraction' => ShopperInteraction::contAuth()->shopperInteraction(), + 'recurringProcessingModel' => RecurringProcessingModel::cardOnFile()->recurringProcessingModel(), + ], $result); + } +} From 0e5376dc276a5cbdb0375e3280e2f3c9f823efc8 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 4 Mar 2022 07:56:18 +0100 Subject: [PATCH 100/136] ASW-476 - CR fixes --- tests/Unit/Models/PaymentResultCodeTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Unit/Models/PaymentResultCodeTest.php b/tests/Unit/Models/PaymentResultCodeTest.php index 304d07ce..f3d9f055 100644 --- a/tests/Unit/Models/PaymentResultCodeTest.php +++ b/tests/Unit/Models/PaymentResultCodeTest.php @@ -35,9 +35,9 @@ public function it_is_immutable_constructed(): void public function it_throws_an_invalid_argument_exception_when_result_code_is_unknown(): void { $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid result code: "test"'); + $this->expectExceptionMessage('Invalid result code: "INVALID_CODE"'); - PaymentResultCode::load('test'); + PaymentResultCode::load('INVALID_CODE'); } /** @test */ @@ -52,7 +52,7 @@ public function it_can_load_a_result_code(): void /** @test */ public function it_knows_when_a_result_code_exists(): void { - $result = PaymentResultCode::exists(PaymentResultCode::cancelled()->resultCode()); + $result = PaymentResultCode::exists('Authorised'); $this->assertTrue($result); } From 5719778c3ecf6001762a3bd0387b137add770281 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 4 Mar 2022 08:56:11 +0100 Subject: [PATCH 101/136] ASW-471 - CR fixes --- .../RecurringPaymentTokenNotFoundException.php | 4 ++-- .../RecurringPaymentTokenNotSavedException.php | 2 +- .../RecurringPaymentTokenNotFoundExceptionTest.php | 13 +++---------- .../RecurringPaymentTokenNotSavedExceptionTest.php | 2 +- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Exceptions/RecurringPaymentTokenNotFoundException.php b/Exceptions/RecurringPaymentTokenNotFoundException.php index b0887d73..af6381b3 100644 --- a/Exceptions/RecurringPaymentTokenNotFoundException.php +++ b/Exceptions/RecurringPaymentTokenNotFoundException.php @@ -11,7 +11,7 @@ final class RecurringPaymentTokenNotFoundException extends \RuntimeException public static function withCustomerIdAndOrderNumber(string $customerId, string $orderNumber): self { return new self(sprintf( - 'Recurring payment token not found with customer id: %s, order number: %s', + 'Recurring payment token not found with customer id: "%s", order number: "%s"', $customerId, $orderNumber )); @@ -20,7 +20,7 @@ public static function withCustomerIdAndOrderNumber(string $customerId, string $ public static function withPendingResultCodeAndPspReference(string $pspReference): self { return new self(sprintf( - 'Recurring payment token not found with result code: %s, psp reference: %s', + 'Recurring payment token not found with result code: "%s", psp reference: "%s"', PaymentResultCode::pending()->resultCode(), $pspReference )); diff --git a/Exceptions/RecurringPaymentTokenNotSavedException.php b/Exceptions/RecurringPaymentTokenNotSavedException.php index 745a446d..28839b50 100644 --- a/Exceptions/RecurringPaymentTokenNotSavedException.php +++ b/Exceptions/RecurringPaymentTokenNotSavedException.php @@ -10,6 +10,6 @@ final class RecurringPaymentTokenNotSavedException extends \RuntimeException { public static function withId(TokenIdentifier $tokenIdentifier): self { - return new self('Recurring payment token not saved with id:'.$tokenIdentifier->identifier()); + return new self('Recurring payment token not saved with id: "'.$tokenIdentifier->identifier().'"'); } } diff --git a/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php b/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php index 1d1770fc..ee859bbe 100644 --- a/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php +++ b/tests/Unit/Exceptions/RecurringPaymentTokenNotFoundExceptionTest.php @@ -33,11 +33,7 @@ public function it_can_be_constructed_with_customer_id_and_order_number(): void self::assertInstanceOf(RecurringPaymentTokenNotFoundException::class, $exception); self::assertEquals( - sprintf( - 'Recurring payment token not found with customer id: %s, order number: %s', - $customerId, - $orderNumber - ), + 'Recurring payment token not found with customer id: "'.$customerId.'", order number: "'.$orderNumber.'"', $exception->getMessage() ); } @@ -51,11 +47,8 @@ public function it_can_be_constructed_with_psp_reference(): void self::assertInstanceOf(RecurringPaymentTokenNotFoundException::class, $exception); self::assertEquals( - sprintf( - 'Recurring payment token not found with result code: %s, psp reference: %s', - PaymentResultCode::pending()->resultCode(), - $pspReference - ), + 'Recurring payment token not found with result code: "'.PaymentResultCode::pending()->resultCode() + .'", psp reference: "'.$pspReference.'"', $exception->getMessage() ); } diff --git a/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php b/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php index 9d0a30ae..8e6e09a6 100644 --- a/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php +++ b/tests/Unit/Exceptions/RecurringPaymentTokenNotSavedExceptionTest.php @@ -32,7 +32,7 @@ public function it_can_be_constructed_with_token_identifier(): void self::assertInstanceOf(RecurringPaymentTokenNotSavedException::class, $exception); self::assertEquals( - 'Recurring payment token not saved with id:'.$tokenIdentifier->identifier(), + 'Recurring payment token not saved with id: "'.$tokenIdentifier->identifier().'"', $exception->getMessage() ); } From 6f3613c516c399718746a3c025a9c0dab4244bb6 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 4 Mar 2022 08:48:04 +0100 Subject: [PATCH 102/136] ASW-469 - CR fixes --- .../InvalidPaymentsResponseException.php | 4 +-- Recurring/Mapper/RecurringTokenMapper.php | 33 ------------------- .../Mapper/RecurringTokenMapperInterface.php | 12 ------- Recurring/RecurringTokenFactory.php | 33 +++++++++++++++++++ Recurring/RecurringTokenFactoryInterface.php | 12 +++++++ ...Test.php => RecurringTokenFactoryTest.php} | 20 +++++------ 6 files changed, 57 insertions(+), 57 deletions(-) delete mode 100644 Recurring/Mapper/RecurringTokenMapper.php delete mode 100644 Recurring/Mapper/RecurringTokenMapperInterface.php create mode 100644 Recurring/RecurringTokenFactory.php create mode 100644 Recurring/RecurringTokenFactoryInterface.php rename tests/Unit/Recurring/{Mapper/RecurringTokenMapperTest.php => RecurringTokenFactoryTest.php} (81%) diff --git a/Exceptions/InvalidPaymentsResponseException.php b/Exceptions/InvalidPaymentsResponseException.php index 9471c296..b03f9b8d 100644 --- a/Exceptions/InvalidPaymentsResponseException.php +++ b/Exceptions/InvalidPaymentsResponseException.php @@ -6,8 +6,8 @@ class InvalidPaymentsResponseException extends \Exception { - public static function invalid(): self + public static function empty(): self { - return new static('Payments response not found.'); + return new static('Empty Payment data.'); } } diff --git a/Recurring/Mapper/RecurringTokenMapper.php b/Recurring/Mapper/RecurringTokenMapper.php deleted file mode 100644 index 4a047089..00000000 --- a/Recurring/Mapper/RecurringTokenMapper.php +++ /dev/null @@ -1,33 +0,0 @@ -recurringTokenMapper = new RecurringTokenMapper(); + $this->recurringTokenMapper = new RecurringTokenFactory(); } /** @test */ public function it_is_a_recurring_token_mapper(): void { - $this->assertInstanceOf(RecurringTokenMapperInterface::class, $this->recurringTokenMapper); + $this->assertInstanceOf(RecurringTokenFactoryInterface::class, $this->recurringTokenMapper); } /** @test */ public function it_throws_invalid_payments_response_exception(): void { $this->expectException(InvalidPaymentsResponseException::class); - $this->expectExceptionMessage('Payments response not found.'); + $this->expectExceptionMessage('Empty Payment data.'); - ($this->recurringTokenMapper)([]); + RecurringTokenFactory::create([]); } /** @test */ @@ -55,7 +55,7 @@ public function it_can_map_from_array(): void ], 'merchantReference' => 'YOUR_ORDER_NUMBER', ]; - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenPaymentsResponseArray); + $recurringPaymentToken = RecurringTokenFactory::create($adyenPaymentsResponseArray); $this->assertEquals('YOUR_UNIQUE_SHOPPER_ID_IOfW3k9G2PvXFu2j', $recurringPaymentToken->customerId()); $this->assertEquals('8415698462516992', $recurringPaymentToken->recurringDetailReference()); @@ -76,7 +76,7 @@ public function it_can_map_default_values(): void 'amount' => [ ], ]; - $recurringPaymentToken = ($this->recurringTokenMapper)($adyenPaymentsResponseArray); + $recurringPaymentToken = RecurringTokenFactory::create($adyenPaymentsResponseArray); $this->assertEquals('', $recurringPaymentToken->customerId()); $this->assertEquals('', $recurringPaymentToken->recurringDetailReference()); From 92e7fd4dd3b5643faf6f46e53b6135b5635c1bb8 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 4 Mar 2022 07:50:37 +0100 Subject: [PATCH 103/136] ASW-472 - CR fixes --- tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php b/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php index 37e307d6..46e9ac55 100644 --- a/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php +++ b/tests/Unit/Models/RecurringPayment/ShopperInteractionTest.php @@ -23,14 +23,14 @@ public function it_contains_a_shopper_interaction(): void } /** @test */ - public function it_can_compare_shopper_interaction_objects(): void + public function it_knows_when_it_equals_a_shopper_interaction(): void { $this->assertTrue($this->shopperInteraction->equals(ShopperInteraction::contAuth())); $this->assertFalse($this->shopperInteraction->equals(ShopperInteraction::ecommerce())); } /** @test */ - public function it_checks_shopper_interaction_on_immutabillity(): void + public function it_is_immutable_constructed(): void { $shopperInteractionContAuth = ShopperInteraction::contAuth(); $this->assertEquals($this->shopperInteraction, $shopperInteractionContAuth); From 13309a6a24b7a5ff1212577d7a839be9934650e8 Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Fri, 4 Mar 2022 17:30:19 +0100 Subject: [PATCH 104/136] ASW-479 Recurring-disable --- AdyenApi/Model/ApiResponse.php | 12 +++++++++ AdyenApi/TransportFactory.php | 35 ++++++++++++++++++++++++++ Components/Adyen/ApiFactory.php | 8 ++++-- Http/Response/ApiJsonResponse.php | 18 +++++++++++++ Http/Response/FrontendJsonResponse.php | 30 ++++++++++++++++++++++ Resources/services/adyen-api.xml | 7 ++++++ Resources/services/http.xml | 2 ++ 7 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 AdyenApi/Model/ApiResponse.php create mode 100644 AdyenApi/TransportFactory.php create mode 100644 Http/Response/ApiJsonResponse.php create mode 100644 Http/Response/FrontendJsonResponse.php create mode 100644 Resources/services/adyen-api.xml diff --git a/AdyenApi/Model/ApiResponse.php b/AdyenApi/Model/ApiResponse.php new file mode 100644 index 00000000..33af297e --- /dev/null +++ b/AdyenApi/Model/ApiResponse.php @@ -0,0 +1,12 @@ +apiFactory = $apiFactory; + } + + public function recurring(Shop $shop): Recurring + { + return new Recurring( + $this->apiFactory->provide($shop) + ); + } + + public function checkout(Shop $shop): Checkout + { + return new Checkout( + $this->apiFactory->provide($shop) + ); + } +} \ No newline at end of file diff --git a/Components/Adyen/ApiFactory.php b/Components/Adyen/ApiFactory.php index f22047e4..9afd9e56 100644 --- a/Components/Adyen/ApiFactory.php +++ b/Components/Adyen/ApiFactory.php @@ -47,8 +47,12 @@ public function provide(Shop $shop): Client ); } - private function createClient(string $merchantAccount, string $apiKey, string $environment, ?string $prefix = null): Client - { + private function createClient( + string $merchantAccount, + string $apiKey, + string $environment, + ?string $prefix = null + ): Client { $urlPrefix = Environment::LIVE === $environment ? $prefix : null; $adyenClient = new Client(); diff --git a/Http/Response/ApiJsonResponse.php b/Http/Response/ApiJsonResponse.php new file mode 100644 index 00000000..f9ae39ca --- /dev/null +++ b/Http/Response/ApiJsonResponse.php @@ -0,0 +1,18 @@ +Plugins()->ViewRenderer()->setNoRender(); + + $httpResponse->setHeader('Content-type', $response->headers->get('Content-Type'), true); + $httpResponse->setHttpResponseCode($response->getStatusCode()); + $httpResponse->setBody($response->getContent()); + + return $httpResponse; + } +} \ No newline at end of file diff --git a/Resources/services/adyen-api.xml b/Resources/services/adyen-api.xml new file mode 100644 index 00000000..41b9161e --- /dev/null +++ b/Resources/services/adyen-api.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Resources/services/http.xml b/Resources/services/http.xml index 38a05be4..bfa7c66d 100644 --- a/Resources/services/http.xml +++ b/Resources/services/http.xml @@ -3,6 +3,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + + Date: Fri, 4 Mar 2022 17:33:13 +0100 Subject: [PATCH 105/136] ASW-479 update cs --- AdyenApi/TransportFactory.php | 2 +- Http/Response/FrontendJsonResponse.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AdyenApi/TransportFactory.php b/AdyenApi/TransportFactory.php index 52ec1d38..d4ea435b 100644 --- a/AdyenApi/TransportFactory.php +++ b/AdyenApi/TransportFactory.php @@ -32,4 +32,4 @@ public function checkout(Shop $shop): Checkout $this->apiFactory->provide($shop) ); } -} \ No newline at end of file +} diff --git a/Http/Response/FrontendJsonResponse.php b/Http/Response/FrontendJsonResponse.php index a7b790ff..8d0014c3 100644 --- a/Http/Response/FrontendJsonResponse.php +++ b/Http/Response/FrontendJsonResponse.php @@ -27,4 +27,4 @@ public function sendJsonResponse( return $httpResponse; } -} \ No newline at end of file +} From bfd0910191beae69b85cb11023afc3d43dbe26c4 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 9 Mar 2022 11:13:40 +0100 Subject: [PATCH 106/136] ASW-499 - Disable token request handler --- .../HttpClient/ClientFactory.php | 18 ++------- .../HttpClient/ClientMemoise.php | 12 ++---- .../HttpClient/ConfigValidator.php | 23 +++-------- AdyenApi/Model/ApiResponse.php | 27 +++++++++++++ .../Recurring/DisableTokenRequestHandler.php | 40 +++++++++++++++++++ .../DisableTokenRequestHandlerInterface.php | 9 +++++ AdyenApi/TransportFactory.php | 6 +-- .../PaymentMethod/PaymentMethodsProvider.php | 6 +-- Components/Adyen/PaymentMethodService.php | 16 +++++++- .../Adyen/PaymentMethodServiceInterface.php | 7 ++-- Components/Adyen/RefundService.php | 27 ++++--------- Controllers/Backend/TestAdyenApi.php | 6 +-- Resources/services/adyen-api.xml | 17 ++++++-- Resources/services/components.xml | 25 +++++------- Resources/services/providers.xml | 2 +- Resources/services/validators.xml | 15 ++++--- 16 files changed, 155 insertions(+), 101 deletions(-) rename Components/Adyen/ApiFactory.php => AdyenApi/HttpClient/ClientFactory.php (85%) rename Components/Adyen/ApiClientMap.php => AdyenApi/HttpClient/ClientMemoise.php (74%) rename Components/Adyen/ApiConfigValidator.php => AdyenApi/HttpClient/ConfigValidator.php (88%) create mode 100644 AdyenApi/Recurring/DisableTokenRequestHandler.php create mode 100644 AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php diff --git a/Components/Adyen/ApiFactory.php b/AdyenApi/HttpClient/ClientFactory.php similarity index 85% rename from Components/Adyen/ApiFactory.php rename to AdyenApi/HttpClient/ClientFactory.php index 9afd9e56..5c467b82 100644 --- a/Components/Adyen/ApiFactory.php +++ b/AdyenApi/HttpClient/ClientFactory.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AdyenPayment\Components\Adyen; +namespace AdyenPayment\AdyenApi\HttpClient; use Adyen\AdyenException; use Adyen\Client; @@ -11,20 +11,10 @@ use Psr\Log\LoggerInterface; use Shopware\Models\Shop\Shop; -/** - * Class ApiFactory. - */ -class ApiFactory +class ClientFactory { - /** - * @var Configuration - */ - private $configuration; - - /** - * @var LoggerInterface - */ - private $logger; + private Configuration $configuration; + private LoggerInterface $logger; public function __construct( Configuration $configuration, diff --git a/Components/Adyen/ApiClientMap.php b/AdyenApi/HttpClient/ClientMemoise.php similarity index 74% rename from Components/Adyen/ApiClientMap.php rename to AdyenApi/HttpClient/ClientMemoise.php index d9d81b96..dbb9968f 100644 --- a/Components/Adyen/ApiClientMap.php +++ b/AdyenApi/HttpClient/ClientMemoise.php @@ -2,24 +2,20 @@ declare(strict_types=1); -namespace AdyenPayment\Components\Adyen; +namespace AdyenPayment\AdyenApi\HttpClient; use Adyen\Client; use Shopware\Models\Shop\Shop; -class ApiClientMap +class ClientMemoise { /** * @var array */ private $memoisedClients = []; + private ClientFactory $factory; - /** - * @var ApiFactory - */ - private $factory; - - public function __construct(ApiFactory $factory) + public function __construct(ClientFactory $factory) { $this->factory = $factory; } diff --git a/Components/Adyen/ApiConfigValidator.php b/AdyenApi/HttpClient/ConfigValidator.php similarity index 88% rename from Components/Adyen/ApiConfigValidator.php rename to AdyenApi/HttpClient/ConfigValidator.php index eb68741f..ea3ac440 100644 --- a/Components/Adyen/ApiConfigValidator.php +++ b/AdyenApi/HttpClient/ConfigValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AdyenPayment\Components\Adyen; +namespace AdyenPayment\AdyenApi\HttpClient; use Adyen\AdyenException; use Adyen\Service\Checkout; @@ -12,25 +12,14 @@ use Shopware\Models\Shop\Shop; use Symfony\Component\Validator\ConstraintViolationList; -class ApiConfigValidator +class ConfigValidator { - /** - * @var ApiFactory - */ - private $adyenApiFactory; - - /** - * @var Configuration - */ - private $configuration; - - /** - * @var ObjectRepository - */ - private $shopRepository; + private ClientFactory $adyenApiFactory; + private Configuration $configuration; + private ObjectRepository $shopRepository; public function __construct( - ApiFactory $adyenApiFactory, + ClientFactory $adyenApiFactory, Configuration $configuration, ObjectRepository $shopRepository ) { diff --git a/AdyenApi/Model/ApiResponse.php b/AdyenApi/Model/ApiResponse.php index 33af297e..50d397e3 100644 --- a/AdyenApi/Model/ApiResponse.php +++ b/AdyenApi/Model/ApiResponse.php @@ -9,4 +9,31 @@ final class ApiResponse private int $statusCode; private bool $success; private string $message; + + private function __construct(int $statusCode, bool $success, string $message) + { + $this->statusCode = $statusCode; + $this->success = $success; + $this->message = $message; + } + + public static function create(int $statusCode, bool $success, string $message): self + { + return new self($statusCode, $success, $message); + } + + public function statusCode(): int + { + return $this->statusCode; + } + + public function isSuccess(): bool + { + return $this->success; + } + + public function message(): string + { + return $this->message; + } } diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php new file mode 100644 index 00000000..a531d0c8 --- /dev/null +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -0,0 +1,40 @@ +paymentMethodService = $paymentMethodService; + $this->transportFactory = $transportFactory; + } + + public function disableToken(string $recurringTokenId, Shop $shop): ?ApiResponse + { + $customerNumber = $this->paymentMethodService->provideCustomerNumber(); + if ('' === $customerNumber) { + return null; + } + $recurringTransport = $this->transportFactory->recurring($shop); + + $payload = [ + 'shopperReference' => $customerNumber, + 'recurringDetailReference' => $recurringTokenId, + ]; + + return ApiResponse::create(...$recurringTransport->disable($payload)); + } +} diff --git a/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php b/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php new file mode 100644 index 00000000..d2ea623a --- /dev/null +++ b/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php @@ -0,0 +1,9 @@ +apiFactory = $apiFactory; } diff --git a/Components/Adyen/PaymentMethod/PaymentMethodsProvider.php b/Components/Adyen/PaymentMethod/PaymentMethodsProvider.php index 76e27a29..f5e9defb 100644 --- a/Components/Adyen/PaymentMethod/PaymentMethodsProvider.php +++ b/Components/Adyen/PaymentMethod/PaymentMethodsProvider.php @@ -6,8 +6,8 @@ use Adyen\AdyenException; use Adyen\Service\Checkout; +use AdyenPayment\AdyenApi\HttpClient\ClientFactory; use AdyenPayment\Collection\Payment\PaymentMethodCollection; -use AdyenPayment\Components\Adyen\ApiFactory; use AdyenPayment\Components\Adyen\PaymentMethodService; use AdyenPayment\Components\Configuration; use Psr\Log\LoggerInterface; @@ -16,12 +16,12 @@ final class PaymentMethodsProvider implements PaymentMethodsProviderInterface { private Configuration $configuration; - private ApiFactory $adyenApiFactory; + private ClientFactory $adyenApiFactory; private LoggerInterface $logger; public function __construct( Configuration $configuration, - ApiFactory $adyenApiFactory, + ClientFactory $adyenApiFactory, LoggerInterface $logger ) { $this->configuration = $configuration; diff --git a/Components/Adyen/PaymentMethodService.php b/Components/Adyen/PaymentMethodService.php index 6873d107..060aa14a 100644 --- a/Components/Adyen/PaymentMethodService.php +++ b/Components/Adyen/PaymentMethodService.php @@ -7,6 +7,7 @@ use Adyen\AdyenException; use Adyen\Service\Checkout; use Adyen\Util\Currency; +use AdyenPayment\AdyenApi\HttpClient\ClientMemoise; use AdyenPayment\Collection\Payment\PaymentMethodCollection; use AdyenPayment\Components\Configuration; use AdyenPayment\Models\Enum\Channel; @@ -17,14 +18,14 @@ final class PaymentMethodService implements PaymentMethodServiceInterface { public const IMPORT_LOCALE = 'en_GB'; - private ApiClientMap $apiClientMap; + private ClientMemoise $apiClientMap; private Configuration $configuration; private array $cache; private LoggerInterface $logger; private CustomerNumberProviderInterface $customerNumberProvider; public function __construct( - ApiClientMap $apiClientMap, + ClientMemoise $apiClientMap, Configuration $configuration, LoggerInterface $logger, CustomerNumberProviderInterface $customerNumberProvider @@ -116,4 +117,15 @@ public function getCheckout(): Checkout ) ); } + + public function provideCustomerNumber(): string + { + $userId = $this->session->get('sUserId'); + if (!$userId) { + return ''; + } + $customer = $this->modelManager->getRepository(Customer::class)->find($userId); + + return $customer ? (string) $customer->getNumber() : ''; + } } diff --git a/Components/Adyen/PaymentMethodServiceInterface.php b/Components/Adyen/PaymentMethodServiceInterface.php index ace594de..23bfdee2 100644 --- a/Components/Adyen/PaymentMethodServiceInterface.php +++ b/Components/Adyen/PaymentMethodServiceInterface.php @@ -17,8 +17,9 @@ public function getPaymentMethods( bool $cache = true ): PaymentMethodCollection; - /** - * @internal - */ + /** @internal */ public function getCheckout(): Checkout; + + /** @internal */ + public function provideCustomerNumber(): string; } diff --git a/Components/Adyen/RefundService.php b/Components/Adyen/RefundService.php index 8585c0c2..a42f32c9 100644 --- a/Components/Adyen/RefundService.php +++ b/Components/Adyen/RefundService.php @@ -6,37 +6,24 @@ use Adyen\AdyenException; use Adyen\Service\Modification; +use AdyenPayment\AdyenApi\HttpClient\ClientMemoise; use AdyenPayment\Components\NotificationManager; use AdyenPayment\Models\Notification; use AdyenPayment\Models\PaymentInfo; use AdyenPayment\Models\Refund; +use Doctrine\ORM\EntityRepository; use Shopware\Components\Model\ModelManager; use Shopware\Models\Order\Order; class RefundService { - /** - * @var ApiClientMap - */ - private $apiClientMap; - - /** - * @var ModelManager - */ - private $modelManager; - - /** - * @var NotificationManager - */ - private $notificationManager; - - /** - * @var \Doctrine\ORM\EntityRepository|\Doctrine\Persistence\ObjectRepository - */ - private $paymentInfoRepository; + private ClientMemoise $apiClientMap; + private ModelManager $modelManager; + private NotificationManager $notificationManager; + private EntityRepository $paymentInfoRepository; public function __construct( - ApiClientMap $apiClientMap, + ClientMemoise $apiClientMap, ModelManager $modelManager, NotificationManager $notificationManager ) { diff --git a/Controllers/Backend/TestAdyenApi.php b/Controllers/Backend/TestAdyenApi.php index 1ae672d3..598a82e6 100644 --- a/Controllers/Backend/TestAdyenApi.php +++ b/Controllers/Backend/TestAdyenApi.php @@ -1,6 +1,6 @@ cacheManager = $this->get(CacheManager::class); - $this->apiConfigValidator = $this->get(ApiConfigValidator::class); + $this->apiConfigValidator = $this->get(ConfigValidator::class); $this->usedFallbackConfigRule = $this->get(UsedFallbackConfigRule::class); } diff --git a/Resources/services/adyen-api.xml b/Resources/services/adyen-api.xml index 41b9161e..204e191b 100644 --- a/Resources/services/adyen-api.xml +++ b/Resources/services/adyen-api.xml @@ -1,7 +1,18 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + + + + + + + + + + + + \ No newline at end of file diff --git a/Resources/services/components.xml b/Resources/services/components.xml index 2bcccb21..9a61989d 100644 --- a/Resources/services/components.xml +++ b/Resources/services/components.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> @@ -26,21 +26,14 @@ - - - - - - - - + - + @@ -133,7 +126,7 @@ + class="AdyenPayment\Components\ShopwareVersionCheck"> @@ -143,11 +136,11 @@ - + decorates="AdyenPayment\Components\Adyen\PaymentMethod\EnrichedPaymentMeanProvider"> + - - + diff --git a/Resources/services/providers.xml b/Resources/services/providers.xml index 5c7267d2..ad4a1fa6 100644 --- a/Resources/services/providers.xml +++ b/Resources/services/providers.xml @@ -5,7 +5,7 @@ - + diff --git a/Resources/services/validators.xml b/Resources/services/validators.xml index c6d9fd14..4311d685 100644 --- a/Resources/services/validators.xml +++ b/Resources/services/validators.xml @@ -1,18 +1,18 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + class="AdyenPayment\Http\Validator\Notification\Chain" public="true"> + decorates="AdyenPayment\Http\Validator\Notification\AuthorizationValidator" public="true"> + id="AdyenPayment\Http\Validator\Notification\LoggingAuthorizationValidatorDecorator.inner"/> @@ -24,9 +24,8 @@ - - - + + service('models').getRepository('Shopware\\Models\\Shop\\Shop') From 6f86d8493dd57aab1483b0668ceeebcb52751d3b Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 9 Mar 2022 11:27:11 +0100 Subject: [PATCH 107/136] ASW-499 - Disable token request handler interface --- AdyenApi/Model/ApiResponse.php | 2 +- AdyenApi/Recurring/DisableTokenRequestHandler.php | 2 +- AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/AdyenApi/Model/ApiResponse.php b/AdyenApi/Model/ApiResponse.php index 50d397e3..feb78d13 100644 --- a/AdyenApi/Model/ApiResponse.php +++ b/AdyenApi/Model/ApiResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AdyenApi\Model; +namespace AdyenPayment\AdyenApi\Model; final class ApiResponse { diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index a531d0c8..8b6fd54e 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -4,7 +4,7 @@ namespace AdyenPayment\AdyenApi\Recurring; -use AdyenApi\Model\ApiResponse; +use AdyenPayment\AdyenApi\Model\ApiResponse; use AdyenPayment\AdyenApi\TransportFactory; use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use Shopware\Models\Shop\Shop; diff --git a/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php b/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php index d2ea623a..8b48786f 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php @@ -4,6 +4,10 @@ namespace AdyenPayment\AdyenApi\Recurring; +use AdyenPayment\AdyenApi\Model\ApiResponse; +use Shopware\Models\Shop\Shop; + interface DisableTokenRequestHandlerInterface { + public function disableToken(string $recurringTokenId, Shop $shop): ?ApiResponse; } From d3f5d2060cc9fa2c88ce210e7f5337ec687af1d9 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 9 Mar 2022 13:08:55 +0100 Subject: [PATCH 108/136] ASW-499 - Refactor and unit tests --- AdyenApi/HttpClient/ClientFactory.php | 12 +- .../HttpClient/ClientFactoryInterface.php | 13 ++ AdyenApi/HttpClient/ClientMemoise.php | 6 +- .../HttpClient/ClientMemoiseInterface.php | 13 ++ AdyenApi/HttpClient/ConfigValidator.php | 14 +- .../HttpClient/ConfigValidatorInterface.php | 12 ++ Components/Configuration.php | 2 +- Components/ConfigurationInterface.php | 25 +++ .../AdyenApi/HttpClient/ClientFactoryTest.php | 62 +++++++ .../AdyenApi/HttpClient/ClientMemoiseTest.php | 49 ++++++ .../HttpClient/ConfigValidatorTest.php | 161 ++++++++++++++++++ 11 files changed, 351 insertions(+), 18 deletions(-) create mode 100644 AdyenApi/HttpClient/ClientFactoryInterface.php create mode 100644 AdyenApi/HttpClient/ClientMemoiseInterface.php create mode 100644 AdyenApi/HttpClient/ConfigValidatorInterface.php create mode 100644 Components/ConfigurationInterface.php create mode 100644 tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php create mode 100644 tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php create mode 100644 tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php diff --git a/AdyenApi/HttpClient/ClientFactory.php b/AdyenApi/HttpClient/ClientFactory.php index 5c467b82..4ce3a94d 100644 --- a/AdyenApi/HttpClient/ClientFactory.php +++ b/AdyenApi/HttpClient/ClientFactory.php @@ -7,19 +7,17 @@ use Adyen\AdyenException; use Adyen\Client; use Adyen\Environment; -use AdyenPayment\Components\Configuration; +use AdyenPayment\Components\ConfigurationInterface; use Psr\Log\LoggerInterface; use Shopware\Models\Shop\Shop; -class ClientFactory +final class ClientFactory implements ClientFactoryInterface { - private Configuration $configuration; + private ConfigurationInterface $configuration; private LoggerInterface $logger; - public function __construct( - Configuration $configuration, - LoggerInterface $logger - ) { + public function __construct(ConfigurationInterface $configuration, LoggerInterface $logger) + { $this->configuration = $configuration; $this->logger = $logger; } diff --git a/AdyenApi/HttpClient/ClientFactoryInterface.php b/AdyenApi/HttpClient/ClientFactoryInterface.php new file mode 100644 index 00000000..6cd6fb44 --- /dev/null +++ b/AdyenApi/HttpClient/ClientFactoryInterface.php @@ -0,0 +1,13 @@ + */ private $memoisedClients = []; - private ClientFactory $factory; + private ClientFactoryInterface $factory; - public function __construct(ClientFactory $factory) + public function __construct(ClientFactoryInterface $factory) { $this->factory = $factory; } diff --git a/AdyenApi/HttpClient/ClientMemoiseInterface.php b/AdyenApi/HttpClient/ClientMemoiseInterface.php new file mode 100644 index 00000000..da6263eb --- /dev/null +++ b/AdyenApi/HttpClient/ClientMemoiseInterface.php @@ -0,0 +1,13 @@ +adyenApiFactory = $adyenApiFactory; @@ -31,7 +31,7 @@ public function __construct( public function validate(int $shopId): ConstraintViolationList { $shop = $this->shopRepository->find($shopId); - if (!$shop) { + if (null === $shop) { return new ConstraintViolationList([ ConstraintViolationFactory::create('Shop not found for ID "'.$shopId.'".'), ]); diff --git a/AdyenApi/HttpClient/ConfigValidatorInterface.php b/AdyenApi/HttpClient/ConfigValidatorInterface.php new file mode 100644 index 00000000..610542b9 --- /dev/null +++ b/AdyenApi/HttpClient/ConfigValidatorInterface.php @@ -0,0 +1,12 @@ +configuration = $this->prophesize(ConfigurationInterface::class); + $this->logger = $this->prophesize(LoggerInterface::class); + $this->clientFactory = new ClientFactory($this->configuration->reveal(), $this->logger->reveal()); + } + + /** @test */ + public function it_is_a_client_factory(): void + { + $this->assertInstanceOf(ClientFactory::class, $this->clientFactory); + } + + /** @test */ + public function it_can_provide_a_client(): void + { + $shop = $this->prophesize(Shop::class); + $shop->getId()->willReturn('shop-id'); + + $this->configuration->getMerchantAccount($shop)->willReturn($merchantAccount = 'mock-merchantAccount'); + $this->configuration->getApiKey($shop)->willReturn($apiKey = 'mock-apiKey'); + $this->configuration->getEnvironment($shop)->willReturn($environment = Environment::TEST); + $this->configuration->getApiUrlPrefix($shop)->willReturn($urlPrefix = 'api-url-prefix'); + + $adyenClient = new Client(); + $adyenClient->setMerchantAccount($merchantAccount); + $adyenClient->setXApiKey($apiKey); + $adyenClient->setEnvironment($environment, $urlPrefix); + $adyenClient->setLogger($this->logger->reveal()); + + $result = $this->clientFactory->provide($shop->reveal()); + + $this->assertEquals($adyenClient, $result); + } +} diff --git a/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php b/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php new file mode 100644 index 00000000..da50b95e --- /dev/null +++ b/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php @@ -0,0 +1,49 @@ +clientFactory = $this->prophesize(ClientFactoryInterface::class); + $this->clientMemoise = new ClientMemoise($this->clientFactory->reveal()); + } + + /** @test */ + public function it_is_a_client_memoise(): void + { + $this->assertInstanceOf(ClientMemoise::class, $this->clientMemoise); + } + + /** @test */ + public function it_can_lookup_a_client(): void + { + $shop = $this->prophesize(Shop::class); + $shop->getId()->willReturn('shop-id'); + + $client = $this->prophesize(Client::class); + + $this->clientFactory->provide($shop->reveal())->willReturn($client->reveal()); + + $result = $this->clientMemoise->lookup($shop->reveal()); + + $this->assertSame($client->reveal(), $result); + } +} diff --git a/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php b/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php new file mode 100644 index 00000000..994fcc9c --- /dev/null +++ b/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php @@ -0,0 +1,161 @@ +adyenApiFactory = $this->prophesize(ClientFactoryInterface::class); + $this->configuration = $this->prophesize(ConfigurationInterface::class); + $this->shopRepository = $this->prophesize(ObjectRepository::class); + + $this->configValidator = new ConfigValidator( + $this->adyenApiFactory->reveal(), + $this->configuration->reveal(), + $this->shopRepository->reveal() + ); + } + + /** @test */ + public function it_is_a_config_validator(): void + { + $this->assertInstanceOf(ConfigValidator::class, $this->configValidator); + } + + /** @test */ + public function it_will_return_a_violation_if_shop_is_not_found(): void + { + $this->shopRepository->find($shopId = 123456)->willReturn(null); + + $this->assertEquals( + new ConstraintViolationList([ + ConstraintViolationFactory::create('Shop not found for ID "'.$shopId.'".'), + ]), + $this->configValidator->validate($shopId) + ); + } + + /** @test */ + public function it_will_return_a_violation_if_the_api_key_was_not_configured(): void + { + $shop = $this->prophesize(Shop::class); + $shop->getId()->willReturn($shopId = 123456); + $this->shopRepository->find($shopId)->willReturn($shop->reveal()); + + $this->configuration->getApiKey($shop)->willReturn(''); + $this->configuration->getMerchantAccount($shop->reveal())->willReturn('merchantAccount'); + + $this->assertEquals( + new ConstraintViolationList([ + ConstraintViolationFactory::create('Missing configuration: API key.'), + ]), + $this->configValidator->validate($shopId) + ); + } + + /** @test */ + public function it_will_return_a_violation_if_the_merchant_account_was_not_configured(): void + { + $shop = $this->prophesize(Shop::class); + $shop->getId()->willReturn($shopId = 123456); + $this->shopRepository->find($shopId)->willReturn($shop->reveal()); + + $this->configuration->getApiKey($shop->reveal())->willReturn('api-key'); + $this->configuration->getMerchantAccount($shop->reveal())->willReturn(''); + + $this->assertEquals( + new ConstraintViolationList([ + ConstraintViolationFactory::create('Missing configuration: merchant account.'), + ]), + $this->configValidator->validate($shopId) + ); + } + + /** @test */ + public function it_will_return_a_violation_if_an_exception_was_throw(): void + { + $shop = $this->prophesize(Shop::class); + $shop->getId()->willReturn($shopId = 123456); + $this->shopRepository->find($shopId)->willReturn($shop->reveal()); + + $this->configuration->getApiKey($shop->reveal())->willReturn('api-key'); + $this->configuration->getMerchantAccount($shop->reveal())->willReturn('merchantAccount'); + // we need to mock a throw exception here because if we don't mock the entire client we would get a + // fatal error instead an exception. + $this->adyenApiFactory->provide($shop->reveal())->willThrow(AdyenException::class); + + $this->assertEquals( + new ConstraintViolationList([ + ConstraintViolationFactory::create('Adyen API failed, check error logs'), + ]), + $this->configValidator->validate($shopId) + ); + } + + /** @test */ + public function it_can_validate_a_config(): void + { + $shop = $this->prophesize(Shop::class); + $shop->getId()->willReturn($shopId = 123456); + + $this->configuration->getApiKey($shop->reveal())->willReturn('api-key'); + $this->configuration->getMerchantAccount($shop->reveal())->willReturn($merchantAccount = 'merchantAccount'); + + $client = $this->createClientMock(); + $this->shopRepository->find($shopId)->willReturn($shop->reveal()); + + $this->adyenApiFactory->provide($shop->reveal())->willReturn($client->reveal()); + $this->configuration->getMerchantAccount($shop->reveal())->willReturn($merchantAccount); + + $this->assertEquals(new ConstraintViolationList(), $this->configValidator->validate($shopId)); + } + + private function createClientMock(): ObjectProphecy + { + // we need to mock these to avoid fatal errors but the expected values are not required for these tests + $config = $this->prophesize(Config::class); + $config->get(Argument::any())->willReturn(Environment::TEST); + $config->getInputType(Argument::any())->willReturn(''); + $httpClient = $this->prophesize(ClientInterface::class); + $httpClient->requestJson(Argument::cetera())->willReturn([]); + + $client = $this->prophesize(Client::class); + $client->getConfig()->willReturn($config->reveal()); + $client->getHttpClient()->willReturn($httpClient->reveal()); + $client->getApiCheckoutVersion()->willReturn(''); + + return $client; + } +} From bff9995ff9b80f41b9567f773eda8fd56f6b2196 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 08:43:29 +0100 Subject: [PATCH 109/136] ASW-499 - Unit tests --- AdyenApi/TransportFactory.php | 9 ++- AdyenApi/TransportFactoryInterface.php | 15 +++++ tests/Unit/AdyenApi/ClientMockTrait.php | 33 ++++++++++ .../HttpClient/ConfigValidatorTest.php | 24 +------ tests/Unit/AdyenApi/TransportFactoryTest.php | 63 +++++++++++++++++++ 5 files changed, 117 insertions(+), 27 deletions(-) create mode 100644 AdyenApi/TransportFactoryInterface.php create mode 100644 tests/Unit/AdyenApi/ClientMockTrait.php create mode 100644 tests/Unit/AdyenApi/TransportFactoryTest.php diff --git a/AdyenApi/TransportFactory.php b/AdyenApi/TransportFactory.php index b52970bf..042d2fac 100644 --- a/AdyenApi/TransportFactory.php +++ b/AdyenApi/TransportFactory.php @@ -6,15 +6,14 @@ use Adyen\Service\Checkout; use Adyen\Service\Recurring; -use AdyenPayment\AdyenApi\HttpClient\ClientFactory; +use AdyenPayment\AdyenApi\HttpClient\ClientFactoryInterface; use Shopware\Models\Shop\Shop; -// TODO add a test -final class TransportFactory +final class TransportFactory implements TransportFactoryInterface { - private ClientFactory $apiFactory; + private ClientFactoryInterface $apiFactory; - public function __construct(ClientFactory $apiFactory) + public function __construct(ClientFactoryInterface $apiFactory) { $this->apiFactory = $apiFactory; } diff --git a/AdyenApi/TransportFactoryInterface.php b/AdyenApi/TransportFactoryInterface.php new file mode 100644 index 00000000..e79d876c --- /dev/null +++ b/AdyenApi/TransportFactoryInterface.php @@ -0,0 +1,15 @@ +prophesize(Config::class); + $config->get(Argument::any())->willReturn(Environment::TEST); + $config->getInputType(Argument::any())->willReturn(''); + $httpClient = $this->prophesize(ClientInterface::class); + $httpClient->requestJson(Argument::cetera())->willReturn([]); + + $client = $this->prophesize(Client::class); + $client->getConfig()->willReturn($config->reveal()); + $client->getHttpClient()->willReturn($httpClient->reveal()); + $client->getApiCheckoutVersion()->willReturn(''); + $client->getApiRecurringVersion()->willReturn(''); + + return $client; + } +} diff --git a/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php b/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php index 994fcc9c..c8d70a8f 100644 --- a/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php +++ b/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php @@ -5,17 +5,13 @@ namespace AdyenPayment\Tests\Unit\AdyenApi\HttpClient; use Adyen\AdyenException; -use Adyen\Client; -use Adyen\Config; -use Adyen\Environment; -use Adyen\HttpClient\ClientInterface; use AdyenPayment\AdyenApi\HttpClient\ClientFactoryInterface; use AdyenPayment\AdyenApi\HttpClient\ConfigValidator; use AdyenPayment\Components\ConfigurationInterface; +use AdyenPayment\Tests\Unit\AdyenApi\ClientMockTrait; use AdyenPayment\Validator\ConstraintViolationFactory; use Doctrine\Persistence\ObjectRepository; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; use Shopware\Models\Shop\Shop; @@ -24,6 +20,7 @@ class ConfigValidatorTest extends TestCase { use ProphecyTrait; + use ClientMockTrait; private ConfigValidator $configValidator; /** @var ClientFactoryInterface|ObjectProphecy */ @@ -141,21 +138,4 @@ public function it_can_validate_a_config(): void $this->assertEquals(new ConstraintViolationList(), $this->configValidator->validate($shopId)); } - - private function createClientMock(): ObjectProphecy - { - // we need to mock these to avoid fatal errors but the expected values are not required for these tests - $config = $this->prophesize(Config::class); - $config->get(Argument::any())->willReturn(Environment::TEST); - $config->getInputType(Argument::any())->willReturn(''); - $httpClient = $this->prophesize(ClientInterface::class); - $httpClient->requestJson(Argument::cetera())->willReturn([]); - - $client = $this->prophesize(Client::class); - $client->getConfig()->willReturn($config->reveal()); - $client->getHttpClient()->willReturn($httpClient->reveal()); - $client->getApiCheckoutVersion()->willReturn(''); - - return $client; - } } diff --git a/tests/Unit/AdyenApi/TransportFactoryTest.php b/tests/Unit/AdyenApi/TransportFactoryTest.php new file mode 100644 index 00000000..9aba970d --- /dev/null +++ b/tests/Unit/AdyenApi/TransportFactoryTest.php @@ -0,0 +1,63 @@ +clientFactory = $this->prophesize(ClientFactoryInterface::class); + $this->transportFactory = new TransportFactory($this->clientFactory->reveal()); + } + + /** @test */ + public function it_is_a_transport_factory(): void + { + $this->assertInstanceOf(TransportFactoryInterface::class, $this->transportFactory); + } + + /** @test */ + public function it_can_provide_a_recurring_client_service(): void + { + $shop = $this->prophesize(Shop::class); + $adyenClient = $this->createClientMock(); + + $this->clientFactory->provide($shop->reveal())->willReturn($adyenClient->reveal()); + + $result = $this->transportFactory->recurring($shop->reveal()); + + $this->assertInstanceOf(Recurring::class, $result); + } + + /** @test */ + public function it_can_provide_a_checkout_client_service(): void + { + $shop = $this->prophesize(Shop::class); + $adyenClient = $this->createClientMock(); + + $this->clientFactory->provide($shop->reveal())->willReturn($adyenClient->reveal()); + + $result = $this->transportFactory->checkout($shop->reveal()); + + $this->assertInstanceOf(Checkout::class, $result); + } +} From 53136067468af88e86c56aab6d1b72f00ccb23cc Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 09:16:34 +0100 Subject: [PATCH 110/136] ASW-499 - DisableTokenRequestHandler unit tests --- .../Recurring/DisableTokenRequestHandler.php | 10 ++- .../DisableTokenRequestHandlerTest.php | 78 +++++++++++++++++++ tests/Unit/AdyenApi/TransportFactoryTest.php | 4 +- 3 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index 8b6fd54e..8b0e6cd6 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -5,18 +5,18 @@ namespace AdyenPayment\AdyenApi\Recurring; use AdyenPayment\AdyenApi\Model\ApiResponse; -use AdyenPayment\AdyenApi\TransportFactory; +use AdyenPayment\AdyenApi\TransportFactoryInterface; use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use Shopware\Models\Shop\Shop; final class DisableTokenRequestHandler implements DisableTokenRequestHandlerInterface { private PaymentMethodServiceInterface $paymentMethodService; - private TransportFactory $transportFactory; + private TransportFactoryInterface $transportFactory; public function __construct( PaymentMethodServiceInterface $paymentMethodService, - TransportFactory $transportFactory + TransportFactoryInterface $transportFactory ) { $this->paymentMethodService = $paymentMethodService; $this->transportFactory = $transportFactory; @@ -35,6 +35,8 @@ public function disableToken(string $recurringTokenId, Shop $shop): ?ApiResponse 'recurringDetailReference' => $recurringTokenId, ]; - return ApiResponse::create(...$recurringTransport->disable($payload)); + $result = $recurringTransport->disable($payload); + + return ApiResponse::create($result['statusCode'], $result['success'], $result['message']); } } diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php new file mode 100644 index 00000000..2af2b945 --- /dev/null +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -0,0 +1,78 @@ +paymentMethodService = $this->prophesize(PaymentMethodServiceInterface::class); + $this->transportFactory = $this->prophesize(TransportFactoryInterface::class); + + $this->disableTokenRequestHandler = new DisableTokenRequestHandler( + $this->paymentMethodService->reveal(), + $this->transportFactory->reveal() + ); + } + + /** @test */ + public function it_is_a_disable_token_request_handler(): void + { + $this->assertInstanceOf(DisableTokenRequestHandlerInterface::class, $this->disableTokenRequestHandler); + } + + /** @test */ + public function it_will_return_null_on_missing_customer_number(): void + { + $shop = $this->prophesize(Shop::class); + $this->paymentMethodService->provideCustomerNumber()->willReturn(''); + + $result = $this->disableTokenRequestHandler->disableToken('recurringTokenId', $shop->reveal()); + + $this->assertNull($result); + } + + /** @test */ + public function it_can_disable_a_token(): void + { + $shop = $this->prophesize(Shop::class); + $recurringTransport = $this->prophesize(Recurring::class); + $payload = [ + 'shopperReference' => $customerNumber = 'customer-number', + 'recurringDetailReference' => $recurringTokenId = 'recurringTokenId', + ]; + $recurringTransport->disable($payload)->willReturn($expected = [ + 'statusCode' => $statusCode = 200, + 'success' => $success = true, + 'message' => $message = 'It worked', + ]); + $this->paymentMethodService->provideCustomerNumber()->willReturn($customerNumber); + $this->transportFactory->recurring($shop->reveal())->willReturn($recurringTransport); + + $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); + + $this->assertEquals(ApiResponse::create($statusCode, $success, $message), $result); + } +} diff --git a/tests/Unit/AdyenApi/TransportFactoryTest.php b/tests/Unit/AdyenApi/TransportFactoryTest.php index 9aba970d..a8fc2655 100644 --- a/tests/Unit/AdyenApi/TransportFactoryTest.php +++ b/tests/Unit/AdyenApi/TransportFactoryTest.php @@ -36,7 +36,7 @@ public function it_is_a_transport_factory(): void } /** @test */ - public function it_can_provide_a_recurring_client_service(): void + public function it_can_provide_a_recurring_transport(): void { $shop = $this->prophesize(Shop::class); $adyenClient = $this->createClientMock(); @@ -49,7 +49,7 @@ public function it_can_provide_a_recurring_client_service(): void } /** @test */ - public function it_can_provide_a_checkout_client_service(): void + public function it_can_provide_a_checkout_transport(): void { $shop = $this->prophesize(Shop::class); $adyenClient = $this->createClientMock(); From 6505e0e98eef990559a68ff16a6be89e33971044 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 09:21:19 +0100 Subject: [PATCH 111/136] ASW-499 - Fix --- .../Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 2af2b945..7cfa1a12 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -11,6 +11,7 @@ use AdyenPayment\AdyenApi\TransportFactoryInterface; use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; use Shopware\Models\Shop\Shop; @@ -48,6 +49,7 @@ public function it_will_return_null_on_missing_customer_number(): void { $shop = $this->prophesize(Shop::class); $this->paymentMethodService->provideCustomerNumber()->willReturn(''); + $this->transportFactory->recurring(Argument::any())->shouldNotBeCalled(); $result = $this->disableTokenRequestHandler->disableToken('recurringTokenId', $shop->reveal()); From a63af4f5955d80828e697052c9e0c905d390fc57 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 09:36:52 +0100 Subject: [PATCH 112/136] ASW-499 - Handler changes --- .../Recurring/DisableTokenRequestHandler.php | 2 +- .../DisableTokenRequestHandlerTest.php | 28 ++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index 8b0e6cd6..2160b852 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -37,6 +37,6 @@ public function disableToken(string $recurringTokenId, Shop $shop): ?ApiResponse $result = $recurringTransport->disable($payload); - return ApiResponse::create($result['statusCode'], $result['success'], $result['message']); + return ApiResponse::create($result['status'], (200 === $result['status']), $result['message']); } } diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 7cfa1a12..207e0347 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -57,7 +57,7 @@ public function it_will_return_null_on_missing_customer_number(): void } /** @test */ - public function it_can_disable_a_token(): void + public function it_will_return_an_api_response_for_disable_token_success(): void { $shop = $this->prophesize(Shop::class); $recurringTransport = $this->prophesize(Recurring::class); @@ -66,8 +66,7 @@ public function it_can_disable_a_token(): void 'recurringDetailReference' => $recurringTokenId = 'recurringTokenId', ]; $recurringTransport->disable($payload)->willReturn($expected = [ - 'statusCode' => $statusCode = 200, - 'success' => $success = true, + 'status' => $statusCode = 200, 'message' => $message = 'It worked', ]); $this->paymentMethodService->provideCustomerNumber()->willReturn($customerNumber); @@ -75,6 +74,27 @@ public function it_can_disable_a_token(): void $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); - $this->assertEquals(ApiResponse::create($statusCode, $success, $message), $result); + $this->assertEquals(ApiResponse::create($statusCode, true, $message), $result); + } + + /** @test */ + public function it_will_return_an_api_response_for_disable_token_error(): void + { + $shop = $this->prophesize(Shop::class); + $recurringTransport = $this->prophesize(Recurring::class); + $payload = [ + 'shopperReference' => $customerNumber = 'customer-number', + 'recurringDetailReference' => $recurringTokenId = 'recurringTokenId', + ]; + $recurringTransport->disable($payload)->willReturn($expected = [ + 'status' => $statusCode = 422, + 'message' => $message = 'PaymentDetail not found', + ]); + $this->paymentMethodService->provideCustomerNumber()->willReturn($customerNumber); + $this->transportFactory->recurring($shop->reveal())->willReturn($recurringTransport); + + $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); + + $this->assertEquals(ApiResponse::create($statusCode, false, $message), $result); } } From 79884fb0fcfeb8aeaa6f74564d24e394b3d4cd4a Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 10:20:48 +0100 Subject: [PATCH 113/136] ASW-499 - FrontendJsonResponse test --- .../DisableTokenRequestHandlerTest.php | 4 +- .../Response/FrontendJsonResponseTest.php | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/Unit/Http/Response/FrontendJsonResponseTest.php diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 207e0347..6e17328c 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -65,7 +65,7 @@ public function it_will_return_an_api_response_for_disable_token_success(): void 'shopperReference' => $customerNumber = 'customer-number', 'recurringDetailReference' => $recurringTokenId = 'recurringTokenId', ]; - $recurringTransport->disable($payload)->willReturn($expected = [ + $recurringTransport->disable($payload)->willReturn([ 'status' => $statusCode = 200, 'message' => $message = 'It worked', ]); @@ -86,7 +86,7 @@ public function it_will_return_an_api_response_for_disable_token_error(): void 'shopperReference' => $customerNumber = 'customer-number', 'recurringDetailReference' => $recurringTokenId = 'recurringTokenId', ]; - $recurringTransport->disable($payload)->willReturn($expected = [ + $recurringTransport->disable($payload)->willReturn([ 'status' => $statusCode = 422, 'message' => $message = 'PaymentDetail not found', ]); diff --git a/tests/Unit/Http/Response/FrontendJsonResponseTest.php b/tests/Unit/Http/Response/FrontendJsonResponseTest.php new file mode 100644 index 00000000..5343fc28 --- /dev/null +++ b/tests/Unit/Http/Response/FrontendJsonResponseTest.php @@ -0,0 +1,56 @@ +apiJsonResponse = new FrontendJsonResponse(); + } + + /** @test */ + public function it_is_an_api_json_response(): void + { + self::assertInstanceOf(ApiJsonResponse::class, $this->apiJsonResponse); + } + + /** @test */ + public function it_can_send_a_json_response(): void + { + $frontController = $this->prophesize(\Enlight_Controller_Front::class); + $httpResponse = $this->prophesize(\Enlight_Controller_Response_ResponseHttp::class); + $response = $this->prophesize(JsonResponse::class); + $plugins = $this->prophesize(\Enlight_Plugin_Namespace_Loader::class); + $viewRenderer = $this->prophesize(\Enlight_Controller_Plugins_ViewRenderer_Bootstrap::class); + + $response->headers = new ResponseHeaderBag(['Content-Type' => 'json']); + $response->getStatusCode()->willReturn($statusCode = 200); + $response->getContent()->willReturn($jsonContent = '{}'); + $viewRenderer->setNoRender()->shouldBeCalled(); + $plugins->ViewRenderer()->willReturn($viewRenderer->reveal()); + $frontController->Plugins()->willReturn($plugins->reveal()); + + $httpResponse->setHeader('Content-type', $response->headers->get('Content-Type'), true)->shouldBeCalled(); + $httpResponse->setHttpResponseCode($statusCode)->shouldBeCalled(); + $httpResponse->setBody($jsonContent)->shouldBeCalled(); + + $result = $this->apiJsonResponse->sendJsonResponse( + $frontController->reveal(), + $httpResponse->reveal(), + $response->reveal() + ); + + self::assertSame($httpResponse->reveal(), $result); + } +} From 2a3db7de3bfdebbba5cb9d5587a1650455331845 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 10:36:53 +0100 Subject: [PATCH 114/136] ASW-499 - Integration test file --- .../Recurring/DisableTokenRequestHandlerTest.php | 15 +++++++++++++++ .../Recurring/DisableTokenRequestHandlerTest.php | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php diff --git a/tests/Integration/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Integration/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php new file mode 100644 index 00000000..aae6e2a9 --- /dev/null +++ b/tests/Integration/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -0,0 +1,15 @@ +markTestIncomplete(); + } +} diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 6e17328c..3dbbbb8e 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AdyenPayment\Tests\Unit\AdyenApi; +namespace AdyenPayment\Tests\Unit\AdyenApi\Recurring; use Adyen\Service\Recurring; use AdyenPayment\AdyenApi\Model\ApiResponse; From 3f8ae1404aa095af34f417b229203c1c1aebf9cc Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 12:36:50 +0100 Subject: [PATCH 115/136] ASW-499 - CR fixes --- AdyenApi/Model/ApiResponse.php | 5 +++ .../Recurring/DisableTokenRequestHandler.php | 5 +-- .../Adyen/PaymentMethodServiceInterface.php | 7 ++-- .../DisableTokenRequestHandlerTest.php | 2 +- tests/Unit/AdyenApi/ClientMockTrait.php | 33 ------------------- .../AdyenApi/HttpClient/ClientFactoryTest.php | 11 +++---- .../AdyenApi/HttpClient/ClientMemoiseTest.php | 17 ++++++++++ .../HttpClient/ConfigValidatorTest.php | 25 ++++++++++++-- .../DisableTokenRequestHandlerTest.php | 4 +-- tests/Unit/AdyenApi/TransportFactoryTest.php | 24 +++++++++++++- .../Response/FrontendJsonResponseTest.php | 19 +++++------ 11 files changed, 92 insertions(+), 60 deletions(-) delete mode 100644 tests/Unit/AdyenApi/ClientMockTrait.php diff --git a/AdyenApi/Model/ApiResponse.php b/AdyenApi/Model/ApiResponse.php index feb78d13..23ba7b2d 100644 --- a/AdyenApi/Model/ApiResponse.php +++ b/AdyenApi/Model/ApiResponse.php @@ -22,6 +22,11 @@ public static function create(int $statusCode, bool $success, string $message): return new self($statusCode, $success, $message); } + public static function empty(): self + { + return new self(400, false, 'Customer number not found.'); + } + public function statusCode(): int { return $this->statusCode; diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index 2160b852..efff04fe 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -22,11 +22,12 @@ public function __construct( $this->transportFactory = $transportFactory; } - public function disableToken(string $recurringTokenId, Shop $shop): ?ApiResponse + public function disableToken(string $recurringTokenId, Shop $shop): ApiResponse { + // @TODO: replace with a new service. $customerNumber = $this->paymentMethodService->provideCustomerNumber(); if ('' === $customerNumber) { - return null; + return ApiResponse::empty(); } $recurringTransport = $this->transportFactory->recurring($shop); diff --git a/Components/Adyen/PaymentMethodServiceInterface.php b/Components/Adyen/PaymentMethodServiceInterface.php index 23bfdee2..f99fdb60 100644 --- a/Components/Adyen/PaymentMethodServiceInterface.php +++ b/Components/Adyen/PaymentMethodServiceInterface.php @@ -17,9 +17,12 @@ public function getPaymentMethods( bool $cache = true ): PaymentMethodCollection; - /** @internal */ + /** + * @deprecated + * @see \AdyenPayment\AdyenApi\TransportFactory::checkout() + */ public function getCheckout(): Checkout; - /** @internal */ + /** @deprecated */ public function provideCustomerNumber(): string; } diff --git a/tests/Integration/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Integration/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index aae6e2a9..ce2fa288 100644 --- a/tests/Integration/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Integration/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -8,7 +8,7 @@ class DisableTokenRequestHandlerTest extends TestCase { - protected function setUp(): void + public function test(): void { $this->markTestIncomplete(); } diff --git a/tests/Unit/AdyenApi/ClientMockTrait.php b/tests/Unit/AdyenApi/ClientMockTrait.php deleted file mode 100644 index 0946c475..00000000 --- a/tests/Unit/AdyenApi/ClientMockTrait.php +++ /dev/null @@ -1,33 +0,0 @@ -prophesize(Config::class); - $config->get(Argument::any())->willReturn(Environment::TEST); - $config->getInputType(Argument::any())->willReturn(''); - $httpClient = $this->prophesize(ClientInterface::class); - $httpClient->requestJson(Argument::cetera())->willReturn([]); - - $client = $this->prophesize(Client::class); - $client->getConfig()->willReturn($config->reveal()); - $client->getHttpClient()->willReturn($httpClient->reveal()); - $client->getApiCheckoutVersion()->willReturn(''); - $client->getApiRecurringVersion()->willReturn(''); - - return $client; - } -} diff --git a/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php b/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php index e8554e90..6b260fda 100644 --- a/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php +++ b/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php @@ -49,14 +49,11 @@ public function it_can_provide_a_client(): void $this->configuration->getEnvironment($shop)->willReturn($environment = Environment::TEST); $this->configuration->getApiUrlPrefix($shop)->willReturn($urlPrefix = 'api-url-prefix'); - $adyenClient = new Client(); - $adyenClient->setMerchantAccount($merchantAccount); - $adyenClient->setXApiKey($apiKey); - $adyenClient->setEnvironment($environment, $urlPrefix); - $adyenClient->setLogger($this->logger->reveal()); - $result = $this->clientFactory->provide($shop->reveal()); - $this->assertEquals($adyenClient, $result); + $this->assertInstanceOf(Client::class, $result); + $this->assertEquals($merchantAccount, $result->getConfig()->getMerchantAccount()); + $this->assertEquals($apiKey, $result->getConfig()->getXApiKey()); + $this->assertEquals($environment, $result->getConfig()->getEnvironment()); } } diff --git a/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php b/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php index da50b95e..8f8c4d3f 100644 --- a/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php +++ b/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php @@ -46,4 +46,21 @@ public function it_can_lookup_a_client(): void $this->assertSame($client->reveal(), $result); } + + /** @test */ + public function it_can_return_a_memoised_client(): void + { + $shop = $this->prophesize(Shop::class); + $shop->getId()->willReturn('shop-id'); + + $client = $this->prophesize(Client::class); + + $this->clientFactory->provide($shop->reveal())->shouldBeCalledOnce()->willReturn($client->reveal()); + + $firstResult = $this->clientMemoise->lookup($shop->reveal()); + $result = $this->clientMemoise->lookup($shop->reveal()); + + $this->assertSame($client->reveal(), $firstResult); + $this->assertSame($client->reveal(), $result); + } } diff --git a/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php b/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php index c8d70a8f..1a1ca8e9 100644 --- a/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php +++ b/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php @@ -5,13 +5,17 @@ namespace AdyenPayment\Tests\Unit\AdyenApi\HttpClient; use Adyen\AdyenException; +use Adyen\Client; +use Adyen\Config; +use Adyen\Environment; +use Adyen\HttpClient\ClientInterface; use AdyenPayment\AdyenApi\HttpClient\ClientFactoryInterface; use AdyenPayment\AdyenApi\HttpClient\ConfigValidator; use AdyenPayment\Components\ConfigurationInterface; -use AdyenPayment\Tests\Unit\AdyenApi\ClientMockTrait; use AdyenPayment\Validator\ConstraintViolationFactory; use Doctrine\Persistence\ObjectRepository; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; use Shopware\Models\Shop\Shop; @@ -20,7 +24,6 @@ class ConfigValidatorTest extends TestCase { use ProphecyTrait; - use ClientMockTrait; private ConfigValidator $configValidator; /** @var ClientFactoryInterface|ObjectProphecy */ @@ -138,4 +141,22 @@ public function it_can_validate_a_config(): void $this->assertEquals(new ConstraintViolationList(), $this->configValidator->validate($shopId)); } + + private function createClientMock(): ObjectProphecy + { + // we need to mock these to avoid fatal errors but the expected values are not required for these tests + $config = $this->prophesize(Config::class); + $config->get(Argument::any())->willReturn(Environment::TEST); + $config->getInputType(Argument::any())->willReturn(''); + $httpClient = $this->prophesize(ClientInterface::class); + $httpClient->requestJson(Argument::cetera())->willReturn([]); + + $client = $this->prophesize(Client::class); + $client->getConfig()->willReturn($config->reveal()); + $client->getHttpClient()->willReturn($httpClient->reveal()); + $client->getApiCheckoutVersion()->willReturn(''); + $client->getApiRecurringVersion()->willReturn(''); + + return $client; + } } diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 3dbbbb8e..4baa958d 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -45,7 +45,7 @@ public function it_is_a_disable_token_request_handler(): void } /** @test */ - public function it_will_return_null_on_missing_customer_number(): void + public function it_will_return_a_400_on_missing_customer_number(): void { $shop = $this->prophesize(Shop::class); $this->paymentMethodService->provideCustomerNumber()->willReturn(''); @@ -53,7 +53,7 @@ public function it_will_return_null_on_missing_customer_number(): void $result = $this->disableTokenRequestHandler->disableToken('recurringTokenId', $shop->reveal()); - $this->assertNull($result); + $this->assertEquals(ApiResponse::empty(), $result); } /** @test */ diff --git a/tests/Unit/AdyenApi/TransportFactoryTest.php b/tests/Unit/AdyenApi/TransportFactoryTest.php index a8fc2655..585e9f7f 100644 --- a/tests/Unit/AdyenApi/TransportFactoryTest.php +++ b/tests/Unit/AdyenApi/TransportFactoryTest.php @@ -4,12 +4,17 @@ namespace AdyenPayment\Tests\Unit\AdyenApi; +use Adyen\Client; +use Adyen\Config; +use Adyen\Environment; +use Adyen\HttpClient\ClientInterface; use Adyen\Service\Checkout; use Adyen\Service\Recurring; use AdyenPayment\AdyenApi\HttpClient\ClientFactoryInterface; use AdyenPayment\AdyenApi\TransportFactory; use AdyenPayment\AdyenApi\TransportFactoryInterface; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; use Shopware\Models\Shop\Shop; @@ -17,7 +22,6 @@ class TransportFactoryTest extends TestCase { use ProphecyTrait; - use ClientMockTrait; private TransportFactory $transportFactory; /** @var ClientFactoryInterface|ObjectProphecy */ @@ -60,4 +64,22 @@ public function it_can_provide_a_checkout_transport(): void $this->assertInstanceOf(Checkout::class, $result); } + + private function createClientMock(): ObjectProphecy + { + // we need to mock these to avoid fatal errors but the expected values are not required for these tests + $config = $this->prophesize(Config::class); + $config->get(Argument::any())->willReturn(Environment::TEST); + $config->getInputType(Argument::any())->willReturn(''); + $httpClient = $this->prophesize(ClientInterface::class); + $httpClient->requestJson(Argument::cetera())->willReturn([]); + + $client = $this->prophesize(Client::class); + $client->getConfig()->willReturn($config->reveal()); + $client->getHttpClient()->willReturn($httpClient->reveal()); + $client->getApiCheckoutVersion()->willReturn(''); + $client->getApiRecurringVersion()->willReturn(''); + + return $client; + } } diff --git a/tests/Unit/Http/Response/FrontendJsonResponseTest.php b/tests/Unit/Http/Response/FrontendJsonResponseTest.php index 5343fc28..a91b54b5 100644 --- a/tests/Unit/Http/Response/FrontendJsonResponseTest.php +++ b/tests/Unit/Http/Response/FrontendJsonResponseTest.php @@ -7,11 +7,13 @@ use AdyenPayment\Http\Response\ApiJsonResponse; use AdyenPayment\Http\Response\FrontendJsonResponse; use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\ResponseHeaderBag; +use Symfony\Component\HttpFoundation\Response; class FrontendJsonResponseTest extends TestCase { + use ProphecyTrait; private ApiJsonResponse $apiJsonResponse; protected function setUp(): void @@ -30,25 +32,22 @@ public function it_can_send_a_json_response(): void { $frontController = $this->prophesize(\Enlight_Controller_Front::class); $httpResponse = $this->prophesize(\Enlight_Controller_Response_ResponseHttp::class); - $response = $this->prophesize(JsonResponse::class); + $response = new JsonResponse([], Response::HTTP_OK); $plugins = $this->prophesize(\Enlight_Plugin_Namespace_Loader::class); $viewRenderer = $this->prophesize(\Enlight_Controller_Plugins_ViewRenderer_Bootstrap::class); - $response->headers = new ResponseHeaderBag(['Content-Type' => 'json']); - $response->getStatusCode()->willReturn($statusCode = 200); - $response->getContent()->willReturn($jsonContent = '{}'); $viewRenderer->setNoRender()->shouldBeCalled(); - $plugins->ViewRenderer()->willReturn($viewRenderer->reveal()); - $frontController->Plugins()->willReturn($plugins->reveal()); + $plugins->ViewRenderer()->willReturn($viewRenderer); + $frontController->Plugins()->willReturn($plugins); $httpResponse->setHeader('Content-type', $response->headers->get('Content-Type'), true)->shouldBeCalled(); - $httpResponse->setHttpResponseCode($statusCode)->shouldBeCalled(); - $httpResponse->setBody($jsonContent)->shouldBeCalled(); + $httpResponse->setHttpResponseCode(Response::HTTP_OK)->shouldBeCalled(); + $httpResponse->setBody($response->getContent())->shouldBeCalled(); $result = $this->apiJsonResponse->sendJsonResponse( $frontController->reveal(), $httpResponse->reveal(), - $response->reveal() + $response ); self::assertSame($httpResponse->reveal(), $result); From 63dece9cc8771e6895eee94cc50383c925db7fab Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 12:40:53 +0100 Subject: [PATCH 116/136] ASW-499 - Logger assert --- tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php b/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php index 6b260fda..2f0c4b09 100644 --- a/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php +++ b/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php @@ -55,5 +55,6 @@ public function it_can_provide_a_client(): void $this->assertEquals($merchantAccount, $result->getConfig()->getMerchantAccount()); $this->assertEquals($apiKey, $result->getConfig()->getXApiKey()); $this->assertEquals($environment, $result->getConfig()->getEnvironment()); + $this->assertEquals($this->logger->reveal(), $result->getLogger()); } } From 53cda6b5fe6949a8fcc2ef4253eb599dc54583d0 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 12:51:05 +0100 Subject: [PATCH 117/136] ASW-499 - Validate message --- AdyenApi/Recurring/DisableTokenRequestHandler.php | 4 +++- .../AdyenApi/Recurring/DisableTokenRequestHandlerTest.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index efff04fe..40a74a84 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -38,6 +38,8 @@ public function disableToken(string $recurringTokenId, Shop $shop): ApiResponse $result = $recurringTransport->disable($payload); - return ApiResponse::create($result['status'], (200 === $result['status']), $result['message']); + $success = (200 === $result['status']) && false !== mb_strpos(($result['message'] ?? ''), 'successfully-disabled'); + + return ApiResponse::create($result['status'], $success, $result['message']); } } diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 4baa958d..4640b357 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -67,7 +67,7 @@ public function it_will_return_an_api_response_for_disable_token_success(): void ]; $recurringTransport->disable($payload)->willReturn([ 'status' => $statusCode = 200, - 'message' => $message = 'It worked', + 'message' => $message = 'successfully-disabled', ]); $this->paymentMethodService->provideCustomerNumber()->willReturn($customerNumber); $this->transportFactory->recurring($shop->reveal())->willReturn($recurringTransport); From 46fba258aa78805e19b8a2b392bf8f312fefe73f Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 13:02:22 +0100 Subject: [PATCH 118/136] ASW-499 - CR change --- AdyenApi/Recurring/DisableTokenRequestHandler.php | 6 ++++-- AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index 40a74a84..0c736b55 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -8,6 +8,7 @@ use AdyenPayment\AdyenApi\TransportFactoryInterface; use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; use Shopware\Models\Shop\Shop; +use Symfony\Component\HttpFoundation\Response; final class DisableTokenRequestHandler implements DisableTokenRequestHandlerInterface { @@ -38,8 +39,9 @@ public function disableToken(string $recurringTokenId, Shop $shop): ApiResponse $result = $recurringTransport->disable($payload); - $success = (200 === $result['status']) && false !== mb_strpos(($result['message'] ?? ''), 'successfully-disabled'); + $validResponse = Response::HTTP_OK === $result['status']; + $validMessage = false !== mb_strpos(($result['message'] ?? ''), 'successfully-disabled'); - return ApiResponse::create($result['status'], $success, $result['message']); + return ApiResponse::create($result['status'], ($validResponse && $validMessage), $result['message']); } } diff --git a/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php b/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php index 8b48786f..27317f1e 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandlerInterface.php @@ -9,5 +9,5 @@ interface DisableTokenRequestHandlerInterface { - public function disableToken(string $recurringTokenId, Shop $shop): ?ApiResponse; + public function disableToken(string $recurringTokenId, Shop $shop): ApiResponse; } From 8ded36f70892811867a64fad4f522522e47f8564 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 11:18:31 +0100 Subject: [PATCH 119/136] ASW-500 - Frontend controller for disable token --- .../Frontend/DisableRecurringToken.php | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Shopware/Controllers/Frontend/DisableRecurringToken.php diff --git a/Shopware/Controllers/Frontend/DisableRecurringToken.php b/Shopware/Controllers/Frontend/DisableRecurringToken.php new file mode 100644 index 00000000..c597d7ab --- /dev/null +++ b/Shopware/Controllers/Frontend/DisableRecurringToken.php @@ -0,0 +1,78 @@ +frontendJsonResponse = $this->get(FrontendJsonResponse::class); + $this->disableTokenRequestHandler = $this->get(DisableTokenRequestHandler::class); + } + + /** + * POST: /disabled + */ + public function disabledAction(): void + { + try { + $recurringToken = $this->Request()->getParams()['recurringToken'] ?? ''; + + if ('' === $recurringToken) { + $this->frontendJsonResponse->sendJsonResponse( + $this->Front(), + $this->Response(), + JsonResponse::create( + ['error' => true, 'message' => 'Missing recurring token param.'], + Response::HTTP_BAD_REQUEST + ) + ); + return; + } + + $result = $this->disableTokenRequestHandler->disableToken($recurringToken, Shopware()->Shop()); + + if (null === $result) { + $this->frontendJsonResponse->sendJsonResponse( + $this->Front(), + $this->Response(), + JsonResponse::create( + ['error' => true, 'message' => 'Missing customer number.'], + Response::HTTP_BAD_REQUEST + ) + ); + return; + } + + $this->frontendJsonResponse->sendJsonResponse( + $this->Front(), + $this->Response(), + JsonResponse::create(['error' => false, 'message' => $result->message()], Response::HTTP_OK) + ); + } catch (\Exception $e) { + $this->frontendJsonResponse->sendJsonResponse( + $this->Front(), + $this->Response(), + JsonResponse::create(['error' => true, 'message' => $e->getMessage()], Response::HTTP_BAD_REQUEST) + ); + } + } + + public function getCSRFProtectedActions() + { + return ['disabledAction']; + } +} \ No newline at end of file From b6a03e4ab873dc21d2b4958fddd560635b07a325 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 13:00:08 +0100 Subject: [PATCH 120/136] ASW-500 - Result changed --- .../Frontend/DisableRecurringToken.php | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/Shopware/Controllers/Frontend/DisableRecurringToken.php b/Shopware/Controllers/Frontend/DisableRecurringToken.php index c597d7ab..f4e3be4a 100644 --- a/Shopware/Controllers/Frontend/DisableRecurringToken.php +++ b/Shopware/Controllers/Frontend/DisableRecurringToken.php @@ -45,22 +45,12 @@ public function disabledAction(): void $result = $this->disableTokenRequestHandler->disableToken($recurringToken, Shopware()->Shop()); - if (null === $result) { - $this->frontendJsonResponse->sendJsonResponse( - $this->Front(), - $this->Response(), - JsonResponse::create( - ['error' => true, 'message' => 'Missing customer number.'], - Response::HTTP_BAD_REQUEST - ) - ); - return; - } - $this->frontendJsonResponse->sendJsonResponse( $this->Front(), $this->Response(), - JsonResponse::create(['error' => false, 'message' => $result->message()], Response::HTTP_OK) + JsonResponse::create( + ['error' => !$result->isSuccess(), 'message' => $result->message()], Response::HTTP_OK + ) ); } catch (\Exception $e) { $this->frontendJsonResponse->sendJsonResponse( From 6b050f1ac5e7c29499b02918290c8dc733861c35 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 10 Mar 2022 13:08:59 +0100 Subject: [PATCH 121/136] ASW-500 - Method name --- Shopware/Controllers/Frontend/DisableRecurringToken.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Shopware/Controllers/Frontend/DisableRecurringToken.php b/Shopware/Controllers/Frontend/DisableRecurringToken.php index f4e3be4a..c636d391 100644 --- a/Shopware/Controllers/Frontend/DisableRecurringToken.php +++ b/Shopware/Controllers/Frontend/DisableRecurringToken.php @@ -26,7 +26,7 @@ public function preDispatch(): void /** * POST: /disabled */ - public function disabledAction(): void + public function disabled(): void { try { $recurringToken = $this->Request()->getParams()['recurringToken'] ?? ''; @@ -63,6 +63,6 @@ public function disabledAction(): void public function getCSRFProtectedActions() { - return ['disabledAction']; + return ['disabled']; } } \ No newline at end of file From ea9688dcab7a0eea1af6c6dc47e7bcc21d22bdd2 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 11 Mar 2022 07:40:19 +0100 Subject: [PATCH 122/136] ASW-500 - Controller name --- Shopware/Controllers/Frontend/DisableRecurringToken.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Shopware/Controllers/Frontend/DisableRecurringToken.php b/Shopware/Controllers/Frontend/DisableRecurringToken.php index c636d391..a705b94b 100644 --- a/Shopware/Controllers/Frontend/DisableRecurringToken.php +++ b/Shopware/Controllers/Frontend/DisableRecurringToken.php @@ -12,7 +12,7 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; -class DisableRecurringToken extends \Enlight_Controller_Action implements CSRFGetProtectionAware +class Shopware_Controllers_Frontend_DisableRecurringToken extends \Enlight_Controller_Action implements CSRFGetProtectionAware { private ApiJsonResponse $frontendJsonResponse; private DisableTokenRequestHandlerInterface $disableTokenRequestHandler; @@ -26,7 +26,7 @@ public function preDispatch(): void /** * POST: /disabled */ - public function disabled(): void + public function disabledAction(): void { try { $recurringToken = $this->Request()->getParams()['recurringToken'] ?? ''; From 7e557d7f71d329a21f9e5b63bf4e7591c5254432 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 11 Mar 2022 07:45:51 +0100 Subject: [PATCH 123/136] ASW-500 - Controller folder --- .../Frontend/DisableRecurringToken.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {Shopware/Controllers => Controllers}/Frontend/DisableRecurringToken.php (100%) diff --git a/Shopware/Controllers/Frontend/DisableRecurringToken.php b/Controllers/Frontend/DisableRecurringToken.php similarity index 100% rename from Shopware/Controllers/Frontend/DisableRecurringToken.php rename to Controllers/Frontend/DisableRecurringToken.php From 036ce5a0ef7c4340b0af57541c78e7f4f790eb95 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 11 Mar 2022 09:59:21 +0100 Subject: [PATCH 124/136] ASW-500 - Config fixes --- .../Frontend/DisableRecurringToken.php | 44 ++++++++++--------- Resources/services/adyen-api.xml | 6 ++- Resources/services/http.xml | 2 +- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/Controllers/Frontend/DisableRecurringToken.php b/Controllers/Frontend/DisableRecurringToken.php index a705b94b..33badad8 100644 --- a/Controllers/Frontend/DisableRecurringToken.php +++ b/Controllers/Frontend/DisableRecurringToken.php @@ -2,8 +2,6 @@ declare(strict_types=1); -namespace AdyenPayment\Shopware\Controllers\Frontend; - use AdyenPayment\AdyenApi\Recurring\DisableTokenRequestHandler; use AdyenPayment\AdyenApi\Recurring\DisableTokenRequestHandlerInterface; use AdyenPayment\Http\Response\ApiJsonResponse; @@ -12,7 +10,8 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; -class Shopware_Controllers_Frontend_DisableRecurringToken extends \Enlight_Controller_Action implements CSRFGetProtectionAware +class Shopware_Controllers_Frontend_DisableRecurringToken extends Enlight_Controller_Action + implements CSRFGetProtectionAware { private ApiJsonResponse $frontendJsonResponse; private DisableTokenRequestHandlerInterface $disableTokenRequestHandler; @@ -23,23 +22,17 @@ public function preDispatch(): void $this->disableTokenRequestHandler = $this->get(DisableTokenRequestHandler::class); } - /** - * POST: /disabled - */ public function disabledAction(): void { try { - $recurringToken = $this->Request()->getParams()['recurringToken'] ?? ''; + if (!$this->Request()->isPost()) { + $this->sendJsonBadRequestResponse('Invalid method.'); + return; + } + $recurringToken = $this->Request()->getParams()['recurringToken'] ?? ''; if ('' === $recurringToken) { - $this->frontendJsonResponse->sendJsonResponse( - $this->Front(), - $this->Response(), - JsonResponse::create( - ['error' => true, 'message' => 'Missing recurring token param.'], - Response::HTTP_BAD_REQUEST - ) - ); + $this->sendJsonBadRequestResponse('Missing recurring token param.'); return; } @@ -49,15 +42,12 @@ public function disabledAction(): void $this->Front(), $this->Response(), JsonResponse::create( - ['error' => !$result->isSuccess(), 'message' => $result->message()], Response::HTTP_OK + ['error' => !$result->isSuccess(), 'message' => $result->message()], + Response::HTTP_OK ) ); } catch (\Exception $e) { - $this->frontendJsonResponse->sendJsonResponse( - $this->Front(), - $this->Response(), - JsonResponse::create(['error' => true, 'message' => $e->getMessage()], Response::HTTP_BAD_REQUEST) - ); + $this->sendJsonBadRequestResponse($e->getMessage()); } } @@ -65,4 +55,16 @@ public function getCSRFProtectedActions() { return ['disabled']; } + + private function sendJsonBadRequestResponse($message): void + { + $this->frontendJsonResponse->sendJsonResponse( + $this->Front(), + $this->Response(), + JsonResponse::create( + ['error' => true, 'message' => $message], + Response::HTTP_BAD_REQUEST + ) + ); + } } \ No newline at end of file diff --git a/Resources/services/adyen-api.xml b/Resources/services/adyen-api.xml index 204e191b..0e9c11d0 100644 --- a/Resources/services/adyen-api.xml +++ b/Resources/services/adyen-api.xml @@ -2,7 +2,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + + + @@ -10,7 +12,7 @@ - + diff --git a/Resources/services/http.xml b/Resources/services/http.xml index bfa7c66d..4088e3e3 100644 --- a/Resources/services/http.xml +++ b/Resources/services/http.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + From 3f2f9c8243911592a807d59fc6672a14314ddf03 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Fri, 11 Mar 2022 11:00:03 +0100 Subject: [PATCH 125/136] ASW-500 - Unit test note --- Controllers/Frontend/DisableRecurringToken.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Controllers/Frontend/DisableRecurringToken.php b/Controllers/Frontend/DisableRecurringToken.php index 33badad8..e0a33a37 100644 --- a/Controllers/Frontend/DisableRecurringToken.php +++ b/Controllers/Frontend/DisableRecurringToken.php @@ -10,6 +10,8 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; +// @TODO: pending test with SW5 PSR-1 autoloading +//phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps class Shopware_Controllers_Frontend_DisableRecurringToken extends Enlight_Controller_Action implements CSRFGetProtectionAware { From 10f9c3940777bd8f70731b5a0c48a682fb0853bc Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 14 Mar 2022 07:45:57 +0100 Subject: [PATCH 126/136] ASW-500 - CR fix --- Controllers/Frontend/DisableRecurringToken.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Controllers/Frontend/DisableRecurringToken.php b/Controllers/Frontend/DisableRecurringToken.php index e0a33a37..124966ae 100644 --- a/Controllers/Frontend/DisableRecurringToken.php +++ b/Controllers/Frontend/DisableRecurringToken.php @@ -6,14 +6,12 @@ use AdyenPayment\AdyenApi\Recurring\DisableTokenRequestHandlerInterface; use AdyenPayment\Http\Response\ApiJsonResponse; use AdyenPayment\Http\Response\FrontendJsonResponse; -use Shopware\Components\CSRFGetProtectionAware; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; // @TODO: pending test with SW5 PSR-1 autoloading //phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace, Squiz.Classes.ValidClassName.NotCamelCaps class Shopware_Controllers_Frontend_DisableRecurringToken extends Enlight_Controller_Action - implements CSRFGetProtectionAware { private ApiJsonResponse $frontendJsonResponse; private DisableTokenRequestHandlerInterface $disableTokenRequestHandler; @@ -53,11 +51,6 @@ public function disabledAction(): void } } - public function getCSRFProtectedActions() - { - return ['disabled']; - } - private function sendJsonBadRequestResponse($message): void { $this->frontendJsonResponse->sendJsonResponse( From 22c67e6bfb5dbc9c23f61bfd210402776bfa3dc2 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Mon, 14 Mar 2022 09:09:32 +0100 Subject: [PATCH 127/136] ASW-500 - Refactor after rebase --- .../Recurring/DisableTokenRequestHandler.php | 13 ++++++------- Components/Adyen/PaymentMethodService.php | 17 ----------------- .../Adyen/PaymentMethodServiceInterface.php | 3 --- Resources/services/adyen-api.xml | 2 +- .../DisableTokenRequestHandlerTest.php | 18 +++++++++--------- 5 files changed, 16 insertions(+), 37 deletions(-) diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index 0c736b55..d902e06c 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -6,27 +6,26 @@ use AdyenPayment\AdyenApi\Model\ApiResponse; use AdyenPayment\AdyenApi\TransportFactoryInterface; -use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; +use AdyenPayment\Session\CustomerNumberProviderInterface; use Shopware\Models\Shop\Shop; use Symfony\Component\HttpFoundation\Response; final class DisableTokenRequestHandler implements DisableTokenRequestHandlerInterface { - private PaymentMethodServiceInterface $paymentMethodService; private TransportFactoryInterface $transportFactory; + private CustomerNumberProviderInterface $customerNumberProvider; public function __construct( - PaymentMethodServiceInterface $paymentMethodService, - TransportFactoryInterface $transportFactory + TransportFactoryInterface $transportFactory, + CustomerNumberProviderInterface $customerNumberProvider ) { - $this->paymentMethodService = $paymentMethodService; $this->transportFactory = $transportFactory; + $this->customerNumberProvider = $customerNumberProvider; } public function disableToken(string $recurringTokenId, Shop $shop): ApiResponse { - // @TODO: replace with a new service. - $customerNumber = $this->paymentMethodService->provideCustomerNumber(); + $customerNumber = ($this->customerNumberProvider)(); if ('' === $customerNumber) { return ApiResponse::empty(); } diff --git a/Components/Adyen/PaymentMethodService.php b/Components/Adyen/PaymentMethodService.php index 060aa14a..f9d590b1 100644 --- a/Components/Adyen/PaymentMethodService.php +++ b/Components/Adyen/PaymentMethodService.php @@ -36,9 +36,6 @@ public function __construct( $this->customerNumberProvider = $customerNumberProvider; } - /** - * @throws AdyenException - */ public function getPaymentMethods( ?string $countryCode = null, ?string $currency = null, @@ -106,9 +103,6 @@ private function getCacheKey(string ...$keys): string return md5(implode(',', $keys)); } - /** - * @throws AdyenException - */ public function getCheckout(): Checkout { return new Checkout( @@ -117,15 +111,4 @@ public function getCheckout(): Checkout ) ); } - - public function provideCustomerNumber(): string - { - $userId = $this->session->get('sUserId'); - if (!$userId) { - return ''; - } - $customer = $this->modelManager->getRepository(Customer::class)->find($userId); - - return $customer ? (string) $customer->getNumber() : ''; - } } diff --git a/Components/Adyen/PaymentMethodServiceInterface.php b/Components/Adyen/PaymentMethodServiceInterface.php index f99fdb60..d7344319 100644 --- a/Components/Adyen/PaymentMethodServiceInterface.php +++ b/Components/Adyen/PaymentMethodServiceInterface.php @@ -22,7 +22,4 @@ public function getPaymentMethods( * @see \AdyenPayment\AdyenApi\TransportFactory::checkout() */ public function getCheckout(): Checkout; - - /** @deprecated */ - public function provideCustomerNumber(): string; } diff --git a/Resources/services/adyen-api.xml b/Resources/services/adyen-api.xml index 0e9c11d0..0239d3d0 100644 --- a/Resources/services/adyen-api.xml +++ b/Resources/services/adyen-api.xml @@ -13,8 +13,8 @@ - + \ No newline at end of file diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 4640b357..7f99ffd9 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -9,7 +9,7 @@ use AdyenPayment\AdyenApi\Recurring\DisableTokenRequestHandler; use AdyenPayment\AdyenApi\Recurring\DisableTokenRequestHandlerInterface; use AdyenPayment\AdyenApi\TransportFactoryInterface; -use AdyenPayment\Components\Adyen\PaymentMethodServiceInterface; +use AdyenPayment\Session\CustomerNumberProviderInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -21,20 +21,20 @@ class DisableTokenRequestHandlerTest extends TestCase use ProphecyTrait; private DisableTokenRequestHandler $disableTokenRequestHandler; - /** @var ObjectProphecy|PaymentMethodServiceInterface */ - private $paymentMethodService; + /** @var CustomerNumberProviderInterface|ObjectProphecy */ + private $customerNumberProvider; /** @var ObjectProphecy|TransportFactoryInterface */ private $transportFactory; protected function setUp(): void { - $this->paymentMethodService = $this->prophesize(PaymentMethodServiceInterface::class); + $this->customerNumberProvider = $this->prophesize(CustomerNumberProviderInterface::class); $this->transportFactory = $this->prophesize(TransportFactoryInterface::class); $this->disableTokenRequestHandler = new DisableTokenRequestHandler( - $this->paymentMethodService->reveal(), - $this->transportFactory->reveal() + $this->transportFactory->reveal(), + $this->customerNumberProvider->reveal() ); } @@ -48,7 +48,7 @@ public function it_is_a_disable_token_request_handler(): void public function it_will_return_a_400_on_missing_customer_number(): void { $shop = $this->prophesize(Shop::class); - $this->paymentMethodService->provideCustomerNumber()->willReturn(''); + $this->customerNumberProvider->__invoke()->willReturn(''); $this->transportFactory->recurring(Argument::any())->shouldNotBeCalled(); $result = $this->disableTokenRequestHandler->disableToken('recurringTokenId', $shop->reveal()); @@ -69,7 +69,7 @@ public function it_will_return_an_api_response_for_disable_token_success(): void 'status' => $statusCode = 200, 'message' => $message = 'successfully-disabled', ]); - $this->paymentMethodService->provideCustomerNumber()->willReturn($customerNumber); + $this->customerNumberProvider->__invoke()->willReturn($customerNumber); $this->transportFactory->recurring($shop->reveal())->willReturn($recurringTransport); $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); @@ -90,7 +90,7 @@ public function it_will_return_an_api_response_for_disable_token_error(): void 'status' => $statusCode = 422, 'message' => $message = 'PaymentDetail not found', ]); - $this->paymentMethodService->provideCustomerNumber()->willReturn($customerNumber); + $this->customerNumberProvider->__invoke()->willReturn($customerNumber); $this->transportFactory->recurring($shop->reveal())->willReturn($recurringTransport); $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); From 34c1e797a2072431b647b38025464abbaa34de13 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 16 Mar 2022 12:25:38 +0100 Subject: [PATCH 128/136] ASW-500 - CR fixes --- .../Recurring/DisableTokenRequestHandler.php | 20 +++++++-- .../Frontend/DisableRecurringToken.php | 45 +++++++++++-------- Http/Response/ApiJsonResponse.php | 8 +++- Http/Response/FrontendJsonResponse.php | 18 +++++++- .../AdyenApi/HttpClient/ClientFactoryTest.php | 25 ++++++++++- .../AdyenApi/HttpClient/ClientMemoiseTest.php | 19 +++----- .../HttpClient/ConfigValidatorTest.php | 33 ++++++-------- .../DisableTokenRequestHandlerTest.php | 8 ++-- 8 files changed, 116 insertions(+), 60 deletions(-) diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index d902e06c..05ebaa97 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -38,9 +38,23 @@ public function disableToken(string $recurringTokenId, Shop $shop): ApiResponse $result = $recurringTransport->disable($payload); - $validResponse = Response::HTTP_OK === $result['status']; - $validMessage = false !== mb_strpos(($result['message'] ?? ''), 'successfully-disabled'); + $resultStatus = $result['status'] ?? 400; + $resultMessage = $result['message'] ?? ''; + $isSuccessfullyDisabled = $this->isSuccessfullyDisabled($resultStatus, $resultMessage); - return ApiResponse::create($result['status'], ($validResponse && $validMessage), $result['message']); + return ApiResponse::create($resultStatus, $isSuccessfullyDisabled, $resultMessage); + } + + private function isSuccessfullyDisabled(int $resultStatus, string $resultMessage): bool + { + if (Response::HTTP_OK !== $resultStatus) { + return false; + } + + if (false === mb_strpos($resultMessage, 'successfully-disabled')) { + return false; + } + + return true; } } diff --git a/Controllers/Frontend/DisableRecurringToken.php b/Controllers/Frontend/DisableRecurringToken.php index 124966ae..03d2be20 100644 --- a/Controllers/Frontend/DisableRecurringToken.php +++ b/Controllers/Frontend/DisableRecurringToken.php @@ -26,40 +26,47 @@ public function disabledAction(): void { try { if (!$this->Request()->isPost()) { - $this->sendJsonBadRequestResponse('Invalid method.'); + $this->frontendJsonResponse->sendJsonBadRequestResponse( + $this->Front(), + $this->Response(), + 'Invalid method.' + ); + return; } $recurringToken = $this->Request()->getParams()['recurringToken'] ?? ''; if ('' === $recurringToken) { - $this->sendJsonBadRequestResponse('Missing recurring token param.'); + $this->frontendJsonResponse->sendJsonBadRequestResponse( + $this->Front(), + $this->Response(), + 'Missing recurring token param.' + ); + return; } $result = $this->disableTokenRequestHandler->disableToken($recurringToken, Shopware()->Shop()); + if (!$result->isSuccess()) { + $this->frontendJsonResponse->sendJsonResponse( + $this->Front(), + $this->Response(), + JsonResponse::create( + ['error' => true, 'message' => $result->message()], + Response::HTTP_OK + ) + ); + + return; + } $this->frontendJsonResponse->sendJsonResponse( $this->Front(), $this->Response(), - JsonResponse::create( - ['error' => !$result->isSuccess(), 'message' => $result->message()], - Response::HTTP_OK - ) + JsonResponse::create(null, Response::HTTP_NO_CONTENT) ); } catch (\Exception $e) { - $this->sendJsonBadRequestResponse($e->getMessage()); + $this->frontendJsonResponse->sendJsonBadRequestResponse($this->Front(), $this->Response(), $e->getMessage()); } } - - private function sendJsonBadRequestResponse($message): void - { - $this->frontendJsonResponse->sendJsonResponse( - $this->Front(), - $this->Response(), - JsonResponse::create( - ['error' => true, 'message' => $message], - Response::HTTP_BAD_REQUEST - ) - ); - } } \ No newline at end of file diff --git a/Http/Response/ApiJsonResponse.php b/Http/Response/ApiJsonResponse.php index f9ae39ca..7077a90f 100644 --- a/Http/Response/ApiJsonResponse.php +++ b/Http/Response/ApiJsonResponse.php @@ -11,8 +11,14 @@ interface ApiJsonResponse { public function sendJsonResponse( - Enlight_Controller_Front $frontController, // ideally injected + Enlight_Controller_Front $frontController, Enlight_Controller_Response_ResponseHttp $httpResponse, JsonResponse $response ): Enlight_Controller_Response_ResponseHttp; + + public function sendJsonBadRequestResponse( + Enlight_Controller_Front $frontController, + Enlight_Controller_Response_ResponseHttp $httpResponse, + string $message + ): Enlight_Controller_Response_ResponseHttp; } diff --git a/Http/Response/FrontendJsonResponse.php b/Http/Response/FrontendJsonResponse.php index 8d0014c3..9e00648b 100644 --- a/Http/Response/FrontendJsonResponse.php +++ b/Http/Response/FrontendJsonResponse.php @@ -7,6 +7,7 @@ use Enlight_Controller_Front; use Enlight_Controller_Response_ResponseHttp; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Response; final class FrontendJsonResponse implements ApiJsonResponse { @@ -15,7 +16,7 @@ public function __construct() } public function sendJsonResponse( - Enlight_Controller_Front $frontController, // ideally injected + Enlight_Controller_Front $frontController, Enlight_Controller_Response_ResponseHttp $httpResponse, JsonResponse $response ): Enlight_Controller_Response_ResponseHttp { @@ -27,4 +28,19 @@ public function sendJsonResponse( return $httpResponse; } + + public function sendJsonBadRequestResponse( + Enlight_Controller_Front $frontController, + Enlight_Controller_Response_ResponseHttp $httpResponse, + string $message + ): Enlight_Controller_Response_ResponseHttp { + return $this->sendJsonResponse( + $frontController, + $httpResponse, + JsonResponse::create( + ['error' => true, 'message' => $message], + Response::HTTP_BAD_REQUEST + ) + ); + } } diff --git a/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php b/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php index 2f0c4b09..324021d9 100644 --- a/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php +++ b/tests/Unit/AdyenApi/HttpClient/ClientFactoryTest.php @@ -39,7 +39,7 @@ public function it_is_a_client_factory(): void } /** @test */ - public function it_can_provide_a_client(): void + public function it_can_provide_a_client_for_test_environment(): void { $shop = $this->prophesize(Shop::class); $shop->getId()->willReturn('shop-id'); @@ -47,6 +47,27 @@ public function it_can_provide_a_client(): void $this->configuration->getMerchantAccount($shop)->willReturn($merchantAccount = 'mock-merchantAccount'); $this->configuration->getApiKey($shop)->willReturn($apiKey = 'mock-apiKey'); $this->configuration->getEnvironment($shop)->willReturn($environment = Environment::TEST); + $this->configuration->getApiUrlPrefix($shop)->willReturn('api-url-prefix'); + + $result = $this->clientFactory->provide($shop->reveal()); + + $this->assertInstanceOf(Client::class, $result); + $this->assertEquals($merchantAccount, $result->getConfig()->getMerchantAccount()); + $this->assertEquals($apiKey, $result->getConfig()->getXApiKey()); + $this->assertEquals($environment, $result->getConfig()->getEnvironment()); + $this->assertEquals(Client::ENDPOINT_TEST, $result->getConfig()->get('endpoint')); + $this->assertEquals($this->logger->reveal(), $result->getLogger()); + } + + /** @test */ + public function it_can_provide_a_client_for_live_environment(): void + { + $shop = $this->prophesize(Shop::class); + $shop->getId()->willReturn('shop-id'); + + $this->configuration->getMerchantAccount($shop)->willReturn($merchantAccount = 'mock-merchantAccount'); + $this->configuration->getApiKey($shop)->willReturn($apiKey = 'mock-apiKey'); + $this->configuration->getEnvironment($shop)->willReturn($environment = Environment::LIVE); $this->configuration->getApiUrlPrefix($shop)->willReturn($urlPrefix = 'api-url-prefix'); $result = $this->clientFactory->provide($shop->reveal()); @@ -55,6 +76,8 @@ public function it_can_provide_a_client(): void $this->assertEquals($merchantAccount, $result->getConfig()->getMerchantAccount()); $this->assertEquals($apiKey, $result->getConfig()->getXApiKey()); $this->assertEquals($environment, $result->getConfig()->getEnvironment()); + $expectedEndpoint = Client::ENDPOINT_PROTOCOL.$urlPrefix.Client::ENDPOINT_LIVE_SUFFIX; + $this->assertEquals($expectedEndpoint, $result->getConfig()->get('endpoint')); $this->assertEquals($this->logger->reveal(), $result->getLogger()); } } diff --git a/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php b/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php index 8f8c4d3f..2df38881 100644 --- a/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php +++ b/tests/Unit/AdyenApi/HttpClient/ClientMemoiseTest.php @@ -35,14 +35,11 @@ public function it_is_a_client_memoise(): void /** @test */ public function it_can_lookup_a_client(): void { - $shop = $this->prophesize(Shop::class); - $shop->getId()->willReturn('shop-id'); - + $shop = new Shop(); $client = $this->prophesize(Client::class); + $this->clientFactory->provide($shop)->willReturn($client); - $this->clientFactory->provide($shop->reveal())->willReturn($client->reveal()); - - $result = $this->clientMemoise->lookup($shop->reveal()); + $result = $this->clientMemoise->lookup($shop); $this->assertSame($client->reveal(), $result); } @@ -50,15 +47,13 @@ public function it_can_lookup_a_client(): void /** @test */ public function it_can_return_a_memoised_client(): void { - $shop = $this->prophesize(Shop::class); - $shop->getId()->willReturn('shop-id'); - + $shop = new Shop(); $client = $this->prophesize(Client::class); - $this->clientFactory->provide($shop->reveal())->shouldBeCalledOnce()->willReturn($client->reveal()); + $this->clientFactory->provide($shop)->shouldBeCalledOnce()->willReturn($client); - $firstResult = $this->clientMemoise->lookup($shop->reveal()); - $result = $this->clientMemoise->lookup($shop->reveal()); + $firstResult = $this->clientMemoise->lookup($shop); + $result = $this->clientMemoise->lookup($shop); $this->assertSame($client->reveal(), $firstResult); $this->assertSame($client->reveal(), $result); diff --git a/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php b/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php index 1a1ca8e9..312d406d 100644 --- a/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php +++ b/tests/Unit/AdyenApi/HttpClient/ConfigValidatorTest.php @@ -59,12 +59,11 @@ public function it_will_return_a_violation_if_shop_is_not_found(): void { $this->shopRepository->find($shopId = 123456)->willReturn(null); - $this->assertEquals( - new ConstraintViolationList([ - ConstraintViolationFactory::create('Shop not found for ID "'.$shopId.'".'), - ]), - $this->configValidator->validate($shopId) - ); + $result = $this->configValidator->validate($shopId); + + $this->assertInstanceOf(ConstraintViolationList::class, $result); + $this->assertCount(1, $result); + $this->assertEquals(ConstraintViolationFactory::create('Shop not found for ID "'.$shopId.'".'), $result->get(0)); } /** @test */ @@ -77,12 +76,11 @@ public function it_will_return_a_violation_if_the_api_key_was_not_configured(): $this->configuration->getApiKey($shop)->willReturn(''); $this->configuration->getMerchantAccount($shop->reveal())->willReturn('merchantAccount'); - $this->assertEquals( - new ConstraintViolationList([ - ConstraintViolationFactory::create('Missing configuration: API key.'), - ]), - $this->configValidator->validate($shopId) - ); + $result = $this->configValidator->validate($shopId); + + $this->assertInstanceOf(ConstraintViolationList::class, $result); + $this->assertCount(1, $result); + $this->assertEquals(ConstraintViolationFactory::create('Missing configuration: API key.'), $result->get(0)); } /** @test */ @@ -104,17 +102,15 @@ public function it_will_return_a_violation_if_the_merchant_account_was_not_confi } /** @test */ - public function it_will_return_a_violation_if_an_exception_was_throw(): void + public function it_will_return_a_violation_on_api_adyen_exception(): void { $shop = $this->prophesize(Shop::class); $shop->getId()->willReturn($shopId = 123456); $this->shopRepository->find($shopId)->willReturn($shop->reveal()); - $this->configuration->getApiKey($shop->reveal())->willReturn('api-key'); - $this->configuration->getMerchantAccount($shop->reveal())->willReturn('merchantAccount'); - // we need to mock a throw exception here because if we don't mock the entire client we would get a - // fatal error instead an exception. - $this->adyenApiFactory->provide($shop->reveal())->willThrow(AdyenException::class); + $this->configuration->getApiKey($shop)->willReturn('api-key'); + $this->configuration->getMerchantAccount($shop)->willReturn('merchantAccount'); + $this->adyenApiFactory->provide($shop)->willThrow(AdyenException::class); $this->assertEquals( new ConstraintViolationList([ @@ -144,7 +140,6 @@ public function it_can_validate_a_config(): void private function createClientMock(): ObjectProphecy { - // we need to mock these to avoid fatal errors but the expected values are not required for these tests $config = $this->prophesize(Config::class); $config->get(Argument::any())->willReturn(Environment::TEST); $config->getInputType(Argument::any())->willReturn(''); diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 7f99ffd9..d654f05d 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -65,12 +65,12 @@ public function it_will_return_an_api_response_for_disable_token_success(): void 'shopperReference' => $customerNumber = 'customer-number', 'recurringDetailReference' => $recurringTokenId = 'recurringTokenId', ]; + $this->customerNumberProvider->__invoke()->willReturn($customerNumber); + $this->transportFactory->recurring($shop)->willReturn($recurringTransport); $recurringTransport->disable($payload)->willReturn([ 'status' => $statusCode = 200, 'message' => $message = 'successfully-disabled', ]); - $this->customerNumberProvider->__invoke()->willReturn($customerNumber); - $this->transportFactory->recurring($shop->reveal())->willReturn($recurringTransport); $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); @@ -86,12 +86,12 @@ public function it_will_return_an_api_response_for_disable_token_error(): void 'shopperReference' => $customerNumber = 'customer-number', 'recurringDetailReference' => $recurringTokenId = 'recurringTokenId', ]; + $this->customerNumberProvider->__invoke()->willReturn($customerNumber); + $this->transportFactory->recurring($shop)->willReturn($recurringTransport); $recurringTransport->disable($payload)->willReturn([ 'status' => $statusCode = 422, 'message' => $message = 'PaymentDetail not found', ]); - $this->customerNumberProvider->__invoke()->willReturn($customerNumber); - $this->transportFactory->recurring($shop->reveal())->willReturn($recurringTransport); $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); From ef9157304797cfcf73182908adf9c9709ae69035 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Wed, 16 Mar 2022 12:31:23 +0100 Subject: [PATCH 129/136] ASW-500 - CR fixes --- .../Recurring/DisableTokenRequestHandlerTest.php | 10 ++++++++-- tests/Unit/AdyenApi/TransportFactoryTest.php | 13 ++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index d654f05d..983a6190 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -74,7 +74,10 @@ public function it_will_return_an_api_response_for_disable_token_success(): void $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); - $this->assertEquals(ApiResponse::create($statusCode, true, $message), $result); + $this->assertInstanceOf(ApiResponse::class, $result); + $this->assertEquals($statusCode, $result->statusCode()); + $this->assertTrue($result->isSuccess()); + $this->assertEquals($message, $result->message()); } /** @test */ @@ -95,6 +98,9 @@ public function it_will_return_an_api_response_for_disable_token_error(): void $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); - $this->assertEquals(ApiResponse::create($statusCode, false, $message), $result); + $this->assertInstanceOf(ApiResponse::class, $result); + $this->assertEquals($statusCode, $result->statusCode()); + $this->assertFalse($result->isSuccess()); + $this->assertEquals($message, $result->message()); } } diff --git a/tests/Unit/AdyenApi/TransportFactoryTest.php b/tests/Unit/AdyenApi/TransportFactoryTest.php index 585e9f7f..038ec72d 100644 --- a/tests/Unit/AdyenApi/TransportFactoryTest.php +++ b/tests/Unit/AdyenApi/TransportFactoryTest.php @@ -42,12 +42,12 @@ public function it_is_a_transport_factory(): void /** @test */ public function it_can_provide_a_recurring_transport(): void { - $shop = $this->prophesize(Shop::class); + $shop = new Shop(); $adyenClient = $this->createClientMock(); - $this->clientFactory->provide($shop->reveal())->willReturn($adyenClient->reveal()); + $this->clientFactory->provide($shop)->willReturn($adyenClient); - $result = $this->transportFactory->recurring($shop->reveal()); + $result = $this->transportFactory->recurring($shop); $this->assertInstanceOf(Recurring::class, $result); } @@ -55,19 +55,18 @@ public function it_can_provide_a_recurring_transport(): void /** @test */ public function it_can_provide_a_checkout_transport(): void { - $shop = $this->prophesize(Shop::class); + $shop = new Shop(); $adyenClient = $this->createClientMock(); - $this->clientFactory->provide($shop->reveal())->willReturn($adyenClient->reveal()); + $this->clientFactory->provide($shop)->willReturn($adyenClient); - $result = $this->transportFactory->checkout($shop->reveal()); + $result = $this->transportFactory->checkout($shop); $this->assertInstanceOf(Checkout::class, $result); } private function createClientMock(): ObjectProphecy { - // we need to mock these to avoid fatal errors but the expected values are not required for these tests $config = $this->prophesize(Config::class); $config->get(Argument::any())->willReturn(Environment::TEST); $config->getInputType(Argument::any())->willReturn(''); From c6cfd9b815d8ec553c1b5f7f50660abc0c5fe57d Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 17 Mar 2022 11:00:16 +0100 Subject: [PATCH 130/136] ASW-500 - CR fixes --- AdyenApi/Recurring/DisableTokenRequestHandler.php | 4 ++-- Http/Response/FrontendJsonResponse.php | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index 05ebaa97..bcab3412 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -38,8 +38,8 @@ public function disableToken(string $recurringTokenId, Shop $shop): ApiResponse $result = $recurringTransport->disable($payload); - $resultStatus = $result['status'] ?? 400; - $resultMessage = $result['message'] ?? ''; + $resultStatus = (int) ($result['status'] ?? 400); + $resultMessage = (string) ($result['message'] ?? ''); $isSuccessfullyDisabled = $this->isSuccessfullyDisabled($resultStatus, $resultMessage); return ApiResponse::create($resultStatus, $isSuccessfullyDisabled, $resultMessage); diff --git a/Http/Response/FrontendJsonResponse.php b/Http/Response/FrontendJsonResponse.php index 9e00648b..73293825 100644 --- a/Http/Response/FrontendJsonResponse.php +++ b/Http/Response/FrontendJsonResponse.php @@ -11,10 +11,6 @@ final class FrontendJsonResponse implements ApiJsonResponse { - public function __construct() - { - } - public function sendJsonResponse( Enlight_Controller_Front $frontController, Enlight_Controller_Response_ResponseHttp $httpResponse, From 45a369dcf3c9eddb6bbb2cd3b00581cc3da3f829 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 17 Mar 2022 10:40:07 +0100 Subject: [PATCH 131/136] ASW-501 - Disable payment button --- .../js/jquery.adyen-disable-payment.js | 60 +++++++++++++++++++ Resources/frontend/js/jquery.plugin-loader.js | 3 +- .../frontend/register/payment_fieldset.tpl | 14 +++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 Resources/frontend/js/jquery.adyen-disable-payment.js diff --git a/Resources/frontend/js/jquery.adyen-disable-payment.js b/Resources/frontend/js/jquery.adyen-disable-payment.js new file mode 100644 index 00000000..44dfebf2 --- /dev/null +++ b/Resources/frontend/js/jquery.adyen-disable-payment.js @@ -0,0 +1,60 @@ +;(function ($) { + 'use strict'; + $.plugin('adyen-disable-payment', { + /** + * Plugin default options. + */ + defaults: { + adyenDisableTokenUrl: '/frontend/disableRecurringToken/disabled', + /** + * Selector for the stored payment "disable" button. + * + * @type {String} + */ + disableTokenSelector: '[data-adyen-disable-payment]', + /** + * @var string errorClass + * CSS classes for the error element + */ + errorClass: 'alert is--error is--rounded is--adyen-error', + /** + * @var string errorClassSelector + * CSS classes selector to clear the error elements + */ + errorClassSelector: '.alert.is--error.is--rounded.is--adyen-error', + /** + * @var string errorMessageClass + * CSS classes for the error message element + */ + errorMessageClass: 'alert--content' + }, + init: function () { + var me = this; + me.$el.on('click', function (e) { + if(0 === me.$el.data('adyenDisablePayment').length){ + return; + } + $.loadingIndicator.open(); + $.post({ + url: me.opts.adyenDisableTokenUrl, + dataType: 'json', + data: {recurringToken: me.$el.data('adyenDisablePayment')}, + success: function (response) { + $.loadingIndicator.close(); + response['error'] === true ? me.appendError(response['message']) : window.location.reload(); + } + }).fail(function(response) { + $.loadingIndicator.close(); + me.appendError(response.responseJSON.message); + }); + }); + }, + appendError: function (message) { + var me = this; + $(me.opts.errorClassSelector).remove(); + var error = $('
').addClass(me.opts.errorClass); + error.append($('
').addClass(me.opts.errorMessageClass).html(message)); + me.$el.parent().append(error); + } + }); +})(jQuery); diff --git a/Resources/frontend/js/jquery.plugin-loader.js b/Resources/frontend/js/jquery.plugin-loader.js index 1dc20fa9..8e2c14af 100644 --- a/Resources/frontend/js/jquery.plugin-loader.js +++ b/Resources/frontend/js/jquery.plugin-loader.js @@ -5,6 +5,7 @@ .addPlugin('.adyen-payment-selection', 'adyen-payment-selection') .addPlugin('*[data-adyen-checkout-error="true"]', 'adyen-checkout-error') .addPlugin('.is--act-confirm', 'adyen-confirm-order') - .addPlugin('.is--act-finish', 'adyen-finish-order'); + .addPlugin('.is--act-finish', 'adyen-finish-order') + .addPlugin('[data-adyen-disable-payment]', 'adyen-disable-payment'); }); })(jQuery); diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl index b9667b9c..bb70e909 100644 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -16,3 +16,17 @@ )} checked="checked"{/if} /> {/block} + +{block name="frontend_register_payment_fieldset_description"} + {$smarty.block.parent} + + {block name="frontend_register_payment_stored_method_action_disable"} + {if $isStoredPayment } +
+ +
+ {/if} + {/block} +{/block} From 12d8589d5a0cb43fe80209c3f50fe7a997b4c9cb Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 17 Mar 2022 12:35:04 +0100 Subject: [PATCH 132/136] ASW-501 - ASW-500 related changes --- AdyenApi/Model/ApiResponse.php | 15 ++++----------- AdyenApi/Recurring/DisableTokenRequestHandler.php | 15 +++++---------- Controllers/Frontend/DisableRecurringToken.php | 4 ++-- .../frontend/js/jquery.adyen-disable-payment.js | 4 ++-- .../Recurring/DisableTokenRequestHandlerTest.php | 5 +---- 5 files changed, 14 insertions(+), 29 deletions(-) diff --git a/AdyenApi/Model/ApiResponse.php b/AdyenApi/Model/ApiResponse.php index 23ba7b2d..45bd19a8 100644 --- a/AdyenApi/Model/ApiResponse.php +++ b/AdyenApi/Model/ApiResponse.php @@ -6,30 +6,23 @@ final class ApiResponse { - private int $statusCode; private bool $success; private string $message; - private function __construct(int $statusCode, bool $success, string $message) + private function __construct(bool $success, string $message) { - $this->statusCode = $statusCode; $this->success = $success; $this->message = $message; } - public static function create(int $statusCode, bool $success, string $message): self + public static function create(bool $success, string $message): self { - return new self($statusCode, $success, $message); + return new self($success, $message); } public static function empty(): self { - return new self(400, false, 'Customer number not found.'); - } - - public function statusCode(): int - { - return $this->statusCode; + return new self(false, 'Customer number not found.'); } public function isSuccess(): bool diff --git a/AdyenApi/Recurring/DisableTokenRequestHandler.php b/AdyenApi/Recurring/DisableTokenRequestHandler.php index bcab3412..bc39da6a 100644 --- a/AdyenApi/Recurring/DisableTokenRequestHandler.php +++ b/AdyenApi/Recurring/DisableTokenRequestHandler.php @@ -8,7 +8,6 @@ use AdyenPayment\AdyenApi\TransportFactoryInterface; use AdyenPayment\Session\CustomerNumberProviderInterface; use Shopware\Models\Shop\Shop; -use Symfony\Component\HttpFoundation\Response; final class DisableTokenRequestHandler implements DisableTokenRequestHandlerInterface { @@ -38,20 +37,16 @@ public function disableToken(string $recurringTokenId, Shop $shop): ApiResponse $result = $recurringTransport->disable($payload); - $resultStatus = (int) ($result['status'] ?? 400); + $response = (string) ($result['response'] ?? ''); $resultMessage = (string) ($result['message'] ?? ''); - $isSuccessfullyDisabled = $this->isSuccessfullyDisabled($resultStatus, $resultMessage); + $isSuccessfullyDisabled = $this->isSuccessfullyDisabled($response); - return ApiResponse::create($resultStatus, $isSuccessfullyDisabled, $resultMessage); + return ApiResponse::create($isSuccessfullyDisabled, $resultMessage); } - private function isSuccessfullyDisabled(int $resultStatus, string $resultMessage): bool + private function isSuccessfullyDisabled(string $response): bool { - if (Response::HTTP_OK !== $resultStatus) { - return false; - } - - if (false === mb_strpos($resultMessage, 'successfully-disabled')) { + if (false === mb_strpos($response, 'successfully-disabled')) { return false; } diff --git a/Controllers/Frontend/DisableRecurringToken.php b/Controllers/Frontend/DisableRecurringToken.php index 03d2be20..d8105b18 100644 --- a/Controllers/Frontend/DisableRecurringToken.php +++ b/Controllers/Frontend/DisableRecurringToken.php @@ -53,7 +53,7 @@ public function disabledAction(): void $this->Response(), JsonResponse::create( ['error' => true, 'message' => $result->message()], - Response::HTTP_OK + Response::HTTP_BAD_REQUEST ) ); @@ -63,7 +63,7 @@ public function disabledAction(): void $this->frontendJsonResponse->sendJsonResponse( $this->Front(), $this->Response(), - JsonResponse::create(null, Response::HTTP_NO_CONTENT) + JsonResponse::create(null, Response::HTTP_OK) ); } catch (\Exception $e) { $this->frontendJsonResponse->sendJsonBadRequestResponse($this->Front(), $this->Response(), $e->getMessage()); diff --git a/Resources/frontend/js/jquery.adyen-disable-payment.js b/Resources/frontend/js/jquery.adyen-disable-payment.js index 44dfebf2..9b59c1f6 100644 --- a/Resources/frontend/js/jquery.adyen-disable-payment.js +++ b/Resources/frontend/js/jquery.adyen-disable-payment.js @@ -39,9 +39,9 @@ url: me.opts.adyenDisableTokenUrl, dataType: 'json', data: {recurringToken: me.$el.data('adyenDisablePayment')}, - success: function (response) { + success: function () { $.loadingIndicator.close(); - response['error'] === true ? me.appendError(response['message']) : window.location.reload(); + window.location.reload(); } }).fail(function(response) { $.loadingIndicator.close(); diff --git a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php index 983a6190..50d9f2e7 100644 --- a/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php +++ b/tests/Unit/AdyenApi/Recurring/DisableTokenRequestHandlerTest.php @@ -68,14 +68,13 @@ public function it_will_return_an_api_response_for_disable_token_success(): void $this->customerNumberProvider->__invoke()->willReturn($customerNumber); $this->transportFactory->recurring($shop)->willReturn($recurringTransport); $recurringTransport->disable($payload)->willReturn([ - 'status' => $statusCode = 200, + 'response' => 'successfully-disabled', 'message' => $message = 'successfully-disabled', ]); $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); $this->assertInstanceOf(ApiResponse::class, $result); - $this->assertEquals($statusCode, $result->statusCode()); $this->assertTrue($result->isSuccess()); $this->assertEquals($message, $result->message()); } @@ -92,14 +91,12 @@ public function it_will_return_an_api_response_for_disable_token_error(): void $this->customerNumberProvider->__invoke()->willReturn($customerNumber); $this->transportFactory->recurring($shop)->willReturn($recurringTransport); $recurringTransport->disable($payload)->willReturn([ - 'status' => $statusCode = 422, 'message' => $message = 'PaymentDetail not found', ]); $result = $this->disableTokenRequestHandler->disableToken($recurringTokenId, $shop->reveal()); $this->assertInstanceOf(ApiResponse::class, $result); - $this->assertEquals($statusCode, $result->statusCode()); $this->assertFalse($result->isSuccess()); $this->assertEquals($message, $result->message()); } From 67d8e8743d4617b31aee8b319da41146902fd86e Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 17 Mar 2022 13:26:25 +0100 Subject: [PATCH 133/136] ASW-501 - CR changes --- .../Frontend/DisableRecurringToken.php | 2 +- .../js/jquery.adyen-disable-payment.js | 34 ++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Controllers/Frontend/DisableRecurringToken.php b/Controllers/Frontend/DisableRecurringToken.php index d8105b18..9ff33d1c 100644 --- a/Controllers/Frontend/DisableRecurringToken.php +++ b/Controllers/Frontend/DisableRecurringToken.php @@ -63,7 +63,7 @@ public function disabledAction(): void $this->frontendJsonResponse->sendJsonResponse( $this->Front(), $this->Response(), - JsonResponse::create(null, Response::HTTP_OK) + JsonResponse::create(null, Response::HTTP_NO_CONTENT) ); } catch (\Exception $e) { $this->frontendJsonResponse->sendJsonBadRequestResponse($this->Front(), $this->Response(), $e->getMessage()); diff --git a/Resources/frontend/js/jquery.adyen-disable-payment.js b/Resources/frontend/js/jquery.adyen-disable-payment.js index 9b59c1f6..42af0151 100644 --- a/Resources/frontend/js/jquery.adyen-disable-payment.js +++ b/Resources/frontend/js/jquery.adyen-disable-payment.js @@ -30,23 +30,25 @@ }, init: function () { var me = this; - me.$el.on('click', function (e) { - if(0 === me.$el.data('adyenDisablePayment').length){ - return; + me.$el.on('click', $.proxy(me.enableDisableButtonClick, me)); + }, + enableDisableButtonClick: function () { + var me = this; + if(0 === me.$el.data('adyenDisablePayment').length){ + return; + } + $.loadingIndicator.open(); + $.post({ + url: me.opts.adyenDisableTokenUrl, + dataType: 'json', + data: {recurringToken: me.$el.data('adyenDisablePayment')}, + success: function () { + window.location.reload(); } - $.loadingIndicator.open(); - $.post({ - url: me.opts.adyenDisableTokenUrl, - dataType: 'json', - data: {recurringToken: me.$el.data('adyenDisablePayment')}, - success: function () { - $.loadingIndicator.close(); - window.location.reload(); - } - }).fail(function(response) { - $.loadingIndicator.close(); - me.appendError(response.responseJSON.message); - }); + }).fail(function(response) { + me.appendError(response.responseJSON.message); + }).always(function() { + $.loadingIndicator.close(); }); }, appendError: function (message) { From 166021c0d5072436670afad9b3ff51495f7f3b38 Mon Sep 17 00:00:00 2001 From: Damian Pastorini Date: Thu, 17 Mar 2022 14:32:17 +0100 Subject: [PATCH 134/136] ASW-501 - API URL --- Resources/frontend/js/jquery.adyen-disable-payment.js | 3 +-- Resources/views/frontend/register/payment_fieldset.tpl | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Resources/frontend/js/jquery.adyen-disable-payment.js b/Resources/frontend/js/jquery.adyen-disable-payment.js index 42af0151..a8c6ab9f 100644 --- a/Resources/frontend/js/jquery.adyen-disable-payment.js +++ b/Resources/frontend/js/jquery.adyen-disable-payment.js @@ -5,7 +5,6 @@ * Plugin default options. */ defaults: { - adyenDisableTokenUrl: '/frontend/disableRecurringToken/disabled', /** * Selector for the stored payment "disable" button. * @@ -39,7 +38,7 @@ } $.loadingIndicator.open(); $.post({ - url: me.opts.adyenDisableTokenUrl, + url: me.$el.data('adyenDisableTokenUrl'), dataType: 'json', data: {recurringToken: me.$el.data('adyenDisablePayment')}, success: function () { diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl index bb70e909..37016b55 100644 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -23,7 +23,10 @@ {block name="frontend_register_payment_stored_method_action_disable"} {if $isStoredPayment }
-
From f2b53c877076a0935e0d5f36e99c0f6b7ac22fac Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Wed, 30 Mar 2022 18:42:14 +0200 Subject: [PATCH 135/136] ASW-501 fix data attributes (url broken) --- .../frontend/js/jquery.adyen-disable-payment.js | 13 ++++++++----- .../views/frontend/register/payment_fieldset.tpl | 3 ++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Resources/frontend/js/jquery.adyen-disable-payment.js b/Resources/frontend/js/jquery.adyen-disable-payment.js index a8c6ab9f..8bdf54a8 100644 --- a/Resources/frontend/js/jquery.adyen-disable-payment.js +++ b/Resources/frontend/js/jquery.adyen-disable-payment.js @@ -5,6 +5,8 @@ * Plugin default options. */ defaults: { + adyenDisableTokenUrl: '', + adyenStoredMethodId: '', /** * Selector for the stored payment "disable" button. * @@ -29,24 +31,25 @@ }, init: function () { var me = this; + me.applyDataAttributes(); me.$el.on('click', $.proxy(me.enableDisableButtonClick, me)); }, enableDisableButtonClick: function () { var me = this; - if(0 === me.$el.data('adyenDisablePayment').length){ + if (0 === me.opts.adyenStoredMethodId.length) { return; } $.loadingIndicator.open(); $.post({ - url: me.$el.data('adyenDisableTokenUrl'), + url: me.opts.adyenDisableTokenUrl, dataType: 'json', - data: {recurringToken: me.$el.data('adyenDisablePayment')}, + data: {recurringToken: me.opts.adyenStoredMethodId}, success: function () { window.location.reload(); } - }).fail(function(response) { + }).fail(function (response) { me.appendError(response.responseJSON.message); - }).always(function() { + }).always(function () { $.loadingIndicator.close(); }); }, diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl index 37016b55..795d6fe9 100644 --- a/Resources/views/frontend/register/payment_fieldset.tpl +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -24,8 +24,9 @@ {if $isStoredPayment }
From f723bf36b3b94a419960d9d9bab546249765de1c Mon Sep 17 00:00:00 2001 From: Filippe Bortels Date: Wed, 30 Mar 2022 18:49:59 +0200 Subject: [PATCH 136/136] ASW-0 update changelog --- plugin.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugin.xml b/plugin.xml index 1ff24f10..89ca7302 100644 --- a/plugin.xml +++ b/plugin.xml @@ -305,4 +305,16 @@ Enable Adyen's stored payment methods feature + + + USP: + * re-enable creation of stored payment methods (Tokenization) for Credit Cards (adyen type: scheme) + * functionality to remove stored payment methods / tokens + + + USP: + * re-enable creation of stored payment methods (Tokenization) for Credit Cards (adyen type: scheme) + * functionality to remove stored payment methods / tokens + +