From 518e15d3d1da706ecba0b91a27f35515db97b535 Mon Sep 17 00:00:00 2001 From: bortefi <44976351+bortefi@users.noreply.github.com> Date: Tue, 8 Feb 2022 15:16:28 +0100 Subject: [PATCH] release 3.4.0 (#204) * ASW-0 update project * ASW-314 fix composer * ASW-315 fix use statements with new SW version * ASW-315 udpate services * ASW-359 refactor google pay, update services * ASW-0 update project * ASW-315 udpate services * ASW-359 refactor google pay, update services * AWS-365 - Payments methods filter on enrich fix * ASW-365 - Payments filter fix * ASW-361 bump php-api-library * ASW-0 improve collection performance * ASW-0 improve return type * ASW-0 bugfix: missing return statement * ASW-0 fix logger in constructor * ASW-0 fix collections * ASW-0 cleanup code negligence * ASW-0 cleanup code negligence * ASW-0 add types to generators! * ASW-0 remove comma * ASW-0 update cs * ASW-0 fix composer diff * ASW-361 fix monolog issue sw57 * ASW-361 fix monolog version to be compatible with SW 5.7.0 - SW 5.7.4 * ASW-361 release 3.1.0 issue monolog and adyen-php-lib fix * ASW-385 add index to column ordernumber on PaymentInfo model * ASW-0 bump version 3.0.1 * Bump version 3.0.2 * Bump version 3.1.0 * ASW-0 update plugin min version * ASW-368 Im allowed from filippe to save the day by fixing directly in release branch 3.1.0 * ASW-0 #192 add twig html esacape * ASW-0 auto determine config files * ASW-388 improve code style * ASW-388 add bitbucket pipelines * ASW-388 update image * ASW-388 optimize bitbucket pipelines * ASW-388 optimize grump prio * bitbucket-pipelines.yml edited online with Bitbucket * bitbucket-pipelines.yml edited online with Bitbucket * bitbucket-pipelines.yml edited online with Bitbucket * ASW-0 update pipelines, include PHPunit setup and test * ASW-0 pipelines * bitbucket-pipelines.yml edited online with Bitbucket * ASW-0 include all ci folders * ASW-0 speed up pipelines * ASW-392 - Preselected payment methods fix * ASW-392 - CR fixes * ASW-391 WIP added debugging * ASW-391 Add session Error messages, show redirect errors in FE * ASW-391 replace docblock with datamember types * AWS-389 - Hide Apple pay on none Safari browsers * ASW-389 - Body class isSafari * ASW-389 - jQuery addClass fix * ASW-389 - ApplePaySession * ASW-389 - Extracted payment methods list * ASW-360 fix command success logging * ASW-360 fix backend controller success logging * ASW-387 improve serialization, add unit tests * ASW-387 fix: hide apple pay (ASW-389) * ASW-387 fix: hide apple pay (ASW-389) * ASW-387 fix: payment flow of issue since 3.0.0 * ASW-387 disable: ASW-392 * ASW-387 update unit test * ASW-387 cleanup * ASW-387 add defualt value on confirm tpl * ASW-387 cleanup * ASW-387 merge master into release 3.2.0 * ASW-425 automate service loading * ASW-425 avoid SQL Violation that closes entity manager * ASW-425 update grumphp config * ASW-428 sanitize name * ASW-428 fix other bugs * ASW-428 wip: be ware Smaug lurks here * ASW-428 improve code base * ASW-428 resolve test tools shopware library conflict * ASW-428 remove composer script, tasks are run from grumphp * ASW-428 cleanup config * ASW-428 improve grumphp * ASW-428 fix strict code * ASW-428 somethimes you just need to go all the way to fix the mess * ASW-428 fix unique name * ASW-428 add final keyaword * ASW-426 restructure backend subscribers * ASW-426 refactor providers * ASW-426 add legacy type converter to unique identifier * ASW-426 final * ASW-381 cleanup * ASW-381 clearify (wip) * ASW-381 plugin id provider * ASW-381 cleanup services, fix googleplay Signed-off-by: Filippe Bortels * ASW-381 fix issue with translated paymentmethod names, change unique identifier to code Signed-off-by: Filippe Bortels * ASW-393 add brand in minimal state so giftcards are supported * ASW-393 refactor giftcards out of minimal state, build it using checkout component data * ASW-393 refactor isGiftCard * ASW-393 add brand in minimal state so giftcards are supported # Conflicts: # Resources/views/frontend/checkout/adyen_configuration.tpl * ASW-393 refactor isGiftCard * ASW-381 clearify (wip) * ASW-392 - Replaced subscriber by frontend check * ASW-392 - CR fix for URL * ASW-392 - CR fix for JSON * ASW-392 - CR fix for URL * ASW-392 refactor let to var, remove optional chaining * ASW-392 rewrite cookie allowed * ASW-392 fix allow cookies * ASW-392 fix rebase issues * ASW-392 remove comments next to cookies allowed * ASW-393 WIP: check session type * ASW-393 add fixes for case init and change payment * ASW-393 fix minimal state from backend on gift cards * ASW-393 fix grumphp blacklist dd regex * ASW-0 update grump config * ASW-0 3.2.0 changelog * ASW-0 update composer * ASW-429 add guzzlehttp * ASW-429 WIP add http client apple pay * ASW-429: WIP add zip extractor and fallback logic * ASW-429 add apple pay certificate decoder unit test * ASW-429 add apple pay certificate encoder unit test * ASW-429 add http code to log level unit test * ASW-429 add response status to log level unit test * ASW-429 add body logging middleware unit test * ASW-429 add header logging middleware unit test * ASW-429 add apple pay unit test * ASW-429 add apple pay handler unit test * ASW-429 add apple pay request unit test * ASW-429 add apple pay response unit test * ASW-429 add certificate writer unit test * ASW-429 WIP add zip extractor unit test * ASW-429 add stream transport factory unit test * ASW-429 remove to/file * ASW-429 add assertions on file removal on CertificateWriterTest * ASW-429 fix ZipExtractorTest * ASW-429 refactor apple pay certificate code review * ASW-429 remove suppress from HeaderLoggingMiddleware * ASW-429 rename service xml * ASW-429 remove body from logging * ASW-429 make PlainTextEncoder final * ASW-429 add original exception to CouldNotWriteCertificate * ASW-429 make CertificateWriter more specific, update tests * ASW-429 refactor ZipExtractorTest * ASW-429 re-add CertificateWriterTest * ASW-429 keep exception history * ASW-429 refactor logging infi * ASW-429 rename ApplePay model to ApplePayCertificate * ASW-429 add parameter base_uri * ASW-429 rename ApplePayRequest to ApplePayCertificateRequest, change tests * ASW-429 refactor handler, decoder and make the shit work * ASW-429 remove comment * ASW-429 rename ApplePayTestCertificate to postfix Test * ASW-429: refactor the shit out of it * ASW-429 change const usage * ASW-429 remove unused dependency * ASW-429 inject stream transport as a factory * ASW-430 WIP add apple pay certificate url rewriter * ASW-430 WIP working url rewrite for cronjob * ASW-430 make certificate available on endpoint * ASW-430 make apple pay certificate available on endpoint using cronjob and live * ASW-430 WIP add ApplePayTransportHandler on install * ASW-430: WIP add import button and functionality * ASW-429 ASW-430 rework Adyen ApplePay Merchant id assocation * ASW-429-430 cleanup config * ASW-429-430 remove obsolete config * ASW-429-430 keep zip fixture * ASW-429 ASW-430 fix type condition * ASW-429 ASW-430 fix type condition, with error code * ASW-429 ASW-430 update composer lock * ASW-0 bump version 3.3.0, add plugin notes * ASW-401: fix adyen plugin compatible with SWAGPayPalUnified * ASW-401 add escapeWithQuotes to Sanitize * ASW-401 add unit test SanitizeTest * ASW-401 add escapeWithQuotes testcase to SwPaymentMeanSerializerTest * ASW-401 remove Object.values on ApplePayMethod and getPaymentMethodId * ASW-401 remove object values on setConfig adyen enriched payment methods * ASW-401 WIP refactor sAdyenConfig using endpoint instead of data attribute * ASW-401 remove data- attribute for sAdyenConfig * ASW-401 refactor urls * ASW-432 handle apple pay component request * ASW-432 make currency dynamic * ASW-432 WIP make adyenOrderTotal available over config api endpoint * ASW-432 fix adyenOrderTotal and currency to be fetched using ajax via config * ASW-432 refactor handle to buildComponentApplePay * ASW-432 refactor ApplePay build component data to checkout component data * ASW-432 remove session from buildcomponentdata and move it to handleComponent * ASW-432 add comment check early return is possible in future * ASW-432 remove todo comment after testing it * ASW-0 update php-cs-fixer-config * ASW-0 update release notes * Release 3.4.0 (#203) * ASW-0 update pipline for master branch * ASW-436 fix nullable data from attribute, add enriched test * ASW-436 handle exceptions * ASW-436 clear config cache on backen api action * ASW-376 - Stored payment methods * ASW-376 - Unit test * ASW-375 - Stored payment umbrella installation * ASW-375 - Query * ASW-375 - Hide from admin * ASW-375 - Unit tests * ASW-375 - CR fixes * ASW-375 - Hide field check * ASW-375 - Hide on backend shipping section * ASW-375 - Secure susbscribers * ASW-375 - ASW-379 - Hide refactor * ASW-375 - CR fixes * ASW-375 - CR fixes * ASW-375 refactor code * ASW-375 rename test case * ASW-375 cs flavour * ASW-375 cleanup code, fix test: use real implementation over mocks * ASW-376 - Unit tests * ASW-376 - CR fixes * ASW-378 - Disabled stored methods pick * ASW-378 - Template fix * ASW-377 - EnrichedPaymentMeanProvider for stored methods * ASW-377 - Stored methods selection * ASW-377 - Payment mean selection * ASW-377 - Subscribers and session handler * ASW-377 - CR fixes * ASW-377 - Stored Method ID save and CR fixes * ASW-377 - PaymentMeanCollection tests * ASW-377 - EnrichedPaymentMeanProviderTest updated * ASW-377 - PaymentMethodEnricher unit test * ASW-377 - Admin get payments refactor and unit tests * ASW-377 - Fixed issue and unit tests * ASW-377 - PersistStoredMethodIdSubscriber unit tests * ASW-377 - Fixed config * ASW-435 - Attribute removed * ASW-377 - CR fixes * ASW-377 - CR fixes * ASW-377 fix add subshops on install/update * ASW-461 - My account preselected stored methods * ASW-461 - Preselected stored methods in checkout * ASW-461 - Fixed unit tests * ASW-461 - New unit test * ASW-461 - Account subscriber unit test * ASW-461 - Account subscriber unit test fix * ASW-461 - Renamed test * ASW-461 - Test clarification * ASW-461 - Unused class * ASW-461 - User preference unit test * ASW-461 - CR fixes * ASW-461 - CR fixes * ASW-461 - CR fixes * ASW-461 - CR fix * ASW-461 - Single fetch fix * ASW-466 - Guests fix * ASW-466 - Fix type * ASW-466 - Test name fix * ASW-466 - CR fix * ASW-0 Bump version 3.3.1 * ASW-0 Bump version 3.4.0, changelog Co-authored-by: Damian Pastorini Co-authored-by: davebueds Co-authored-by: Damian Pastorini Co-authored-by: davebueds Co-authored-by: Damian Pastorini --- AdyenPayment.php | 52 ++- Collection/Payment/PaymentMeanCollection.php | 82 +++-- .../Payment/PaymentMethodCollection.php | 6 +- .../EnrichedPaymentMeanProvider.php | 71 +++-- .../StoredPaymentMeanProvider.php | 51 +++ .../StoredPaymentMeanProviderInterface.php | 13 + .../TraceableEnrichedPaymentMeanProvider.php | 36 +++ Components/Adyen/PaymentMethodService.php | 2 +- .../Adyen/PaymentMethodServiceInterface.php | 24 ++ Components/BasketService.php | 2 +- Components/Manager/UserPreferenceManager.php | 24 ++ .../UserPreferenceManagerInterface.php | 12 + Controllers/Backend/AdyenPaymentRefund.php | 6 +- Controllers/Backend/ImportPaymentMethods.php | 8 +- Controllers/Backend/TestAdyenApi.php | 7 +- Doctrine/Writer/PaymentAttributeWriter.php | 6 +- Enricher/Payment/PaymentMethodEnricher.php | 27 +- .../UmbrellaPaymentMeanNotFoundException.php | 13 + Models/Payment/PaymentMean.php | 11 +- Models/Payment/PaymentMethod.php | 4 +- Models/PaymentInfo.php | 18 ++ Models/UserPreference.php | 81 +++++ .../js/jquery.adyen-payment-selection.js | 27 +- Resources/services/applepay-merchant.xml | 2 +- Resources/services/components.xml | 37 ++- Resources/services/managers.xml | 3 + Resources/services/providers.xml | 4 + Resources/services/shopware.xml | 2 +- Resources/services/subscribers.xml | 33 +- .../frontend/checkout/change_payment.tpl | 1 + .../frontend/register/payment_fieldset.tpl | 18 ++ Shopware/Provider/PaymentMeansProvider.php | 13 + .../PaymentMeansProviderInterface.php | 10 + .../SaveStoredMethodPreferenceSubscriber.php | 64 ++++ .../AddStoredMethodIdOnOrderSubscriber.php | 55 ++++ .../Backend/HideStoredPaymentsSubscriber.php | 53 ++++ .../EnrichUmbrellaPaymentMeanSubscriber.php | 78 +++++ .../EnrichUserAdditionalPaymentSubscriber.php | 38 ++- .../PersistStoredMethodIdSubscriber.php | 38 +++ Subscriber/EnrichUserPreferenceSubscriber.php | 49 +++ bitbucket-pipelines.yml | 1 + grumphp.yml.dist | 2 +- plugin.xml | 18 +- ...per-merchantid-domain-association.archive} | Bin .../Payment/PaymentMeanCollectionTest.php | 183 +++++++++++ .../Payment/PaymentMethodCollectionTest.php | 150 +++++++++ .../EnrichedPaymentMeanProviderTest.php | 296 ++++++++++++++++++ .../StoredPaymentMeanProviderTest.php | 82 +++++ ...aceableEnrichedPaymentMeanProviderTest.php | 80 +++++ .../Manager/UserPreferenceManagerTest.php | 50 +++ .../Payment/PaymentMethodEnricherTest.php | 115 +++++++ tests/Unit/Mock/ControllerActionMock.php | 9 + tests/Unit/Models/Payment/PaymentMeanTest.php | 17 +- ...veStoredMethodPreferenceSubscriberTest.php | 203 ++++++++++++ .../HideStoredPaymentsSubscriberTest.php | 119 +++++++ ...nrichUmbrellaPaymentMeanSubscriberTest.php | 174 ++++++++++ ...ichUserAdditionalPaymentSubscriberTest.php | 168 ++++++++++ .../PersistStoredMehtodIdSubscriberTest.php | 90 ++++++ .../EnrichUserPreferenceSubscriberTest.php | 105 +++++++ tests/Unit/Subscriber/SubscriberTestCase.php | 42 +++ 60 files changed, 2857 insertions(+), 128 deletions(-) create mode 100644 Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php create mode 100644 Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php create mode 100644 Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProvider.php create mode 100644 Components/Adyen/PaymentMethodServiceInterface.php create mode 100644 Components/Manager/UserPreferenceManager.php create mode 100644 Components/Manager/UserPreferenceManagerInterface.php create mode 100644 Exceptions/UmbrellaPaymentMeanNotFoundException.php create mode 100644 Models/UserPreference.php create mode 100644 Resources/views/frontend/register/payment_fieldset.tpl create mode 100644 Shopware/Provider/PaymentMeansProvider.php create mode 100644 Shopware/Provider/PaymentMeansProviderInterface.php create mode 100644 Subscriber/Account/SaveStoredMethodPreferenceSubscriber.php create mode 100644 Subscriber/AddStoredMethodIdOnOrderSubscriber.php create mode 100644 Subscriber/Backend/HideStoredPaymentsSubscriber.php create mode 100644 Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php create mode 100644 Subscriber/Checkout/PersistStoredMethodIdSubscriber.php create mode 100755 Subscriber/EnrichUserPreferenceSubscriber.php rename storage/{apple-developer-merchantid-domain-association.zip => apple-developer-merchantid-domain-association.archive} (100%) create mode 100644 tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php create mode 100644 tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php create mode 100644 tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php create mode 100644 tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php create mode 100644 tests/Unit/Components/Adyen/PaymentMethod/TraceableEnrichedPaymentMeanProviderTest.php create mode 100644 tests/Unit/Components/Manager/UserPreferenceManagerTest.php create mode 100644 tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php create mode 100644 tests/Unit/Mock/ControllerActionMock.php create mode 100644 tests/Unit/Subscriber/Account/SaveStoredMethodPreferenceSubscriberTest.php create mode 100644 tests/Unit/Subscriber/Backend/HideStoredPaymentsSubscriberTest.php create mode 100644 tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php create mode 100644 tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php create mode 100644 tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php create mode 100644 tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php create mode 100644 tests/Unit/Subscriber/SubscriberTestCase.php diff --git a/AdyenPayment.php b/AdyenPayment.php index 81fd409d..44476daa 100644 --- a/AdyenPayment.php +++ b/AdyenPayment.php @@ -7,18 +7,23 @@ 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; use AdyenPayment\Models\TextNotification; +use AdyenPayment\Models\UserPreference; 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 Shopware\Models\Shop\Shop; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -29,9 +34,10 @@ 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'; + public const SESSION_ADYEN_STORED_METHOD_ID = 'adyenStoredMethodId'; public static function isPackage(): bool { @@ -82,6 +88,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 +98,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(); @@ -129,7 +137,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(); } @@ -150,16 +157,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(); } @@ -173,6 +170,7 @@ private function getModelMetaData(): array $entityManager->getClassMetadata(PaymentInfo::class), $entityManager->getClassMetadata(Refund::class), $entityManager->getClassMetadata(TextNotification::class), + $entityManager->getClassMetadata(UserPreference::class), ]; } @@ -187,6 +185,36 @@ 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); + + $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); + $payment->setSource(SourceType::adyen()->getType()); + $payment->setHide(true); + $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', + [':name' => self::ADYEN_STORED_PAYMENT_UMBRELLA_CODE] + )['id'] ?? null; + + if (null === $paymentId) { + $modelsManager->persist($payment); + $modelsManager->flush($payment); + } + } } if (AdyenPayment::isPackage()) { diff --git a/Collection/Payment/PaymentMeanCollection.php b/Collection/Payment/PaymentMeanCollection.php index ea797942..eba89f3b 100644 --- a/Collection/Payment/PaymentMeanCollection.php +++ b/Collection/Payment/PaymentMeanCollection.php @@ -4,12 +4,11 @@ namespace AdyenPayment\Collection\Payment; +use AdyenPayment\AdyenPayment; 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 +22,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 +54,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,27 +63,70 @@ 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 filterByAdyenSource(): self + public function filterExcludeHidden(): self + { + return new self(...array_filter( + $this->paymentMeans, + static fn(PaymentMean $paymentMean): bool => !$paymentMean->isHidden() + )); + } + + public function fetchStoredMethodUmbrellaPaymentMean(): ?PaymentMean + { + foreach ($this->paymentMeans as $paymentMean) { + if (AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE === $paymentMean->getValue('name')) { + return $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) { + if ($paymentMean->getValue('stored_method_id') === $storedMethodId) { + return $paymentMean; + } + } + + return null; + } + + public function fetchByUmbrellaStoredMethodId(string $storedMethodId): ?PaymentMean { - return $this->filterBySource(SourceType::adyen()); + 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) { - $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 00d865e8..110d3a15 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'] ?? [] ) ); } @@ -79,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 74ed0efe..4dfb1640 100644 --- a/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php +++ b/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProvider.php @@ -4,23 +4,25 @@ 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\PaymentMethodService; +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; -use Shopware\Bundle\StoreFrontBundle\Struct\Attribute; +use AdyenPayment\Models\Payment\PaymentMethod; 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 ) { @@ -29,9 +31,6 @@ public function __construct( $this->paymentMethodEnricher = $paymentMethodEnricher; } - /** - * @throws \Adyen\AdyenException - */ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollection { $paymentMethodOptions = ($this->paymentMethodOptionsBuilder)(); @@ -45,32 +44,52 @@ public function __invoke(PaymentMeanCollection $paymentMeans): PaymentMeanCollec $paymentMethodOptions['value'] ); - $enricher = $this->paymentMethodEnricher; - - return new PaymentMeanCollection(...$paymentMeans->map( - static function(PaymentMean $shopwareMethod) use ($adyenPaymentMethods, $enricher): ?PaymentMean { - if (!$shopwareMethod->getSource()->equals(SourceType::adyen())) { - return $shopwareMethod; - } + $umbrellaPaymentMean = $paymentMeans->fetchStoredMethodUmbrellaPaymentMean(); + if (null === $umbrellaPaymentMean) { + throw UmbrellaPaymentMeanNotFoundException::missingUmbrellaPaymentMean(); + } - /** @var Attribute $attribute */ - $attribute = $shopwareMethod->getValue('attribute'); - if (!$attribute) { - return $shopwareMethod; - } + return new PaymentMeanCollection( + ...$this->provideEnrichedPaymentMeans($paymentMeans, $adyenPaymentMethods), + ...$this->provideEnrichedStoredPaymentMeans($adyenPaymentMethods, $umbrellaPaymentMean) + ); + } - $identifierOrStoredId = '' !== (string) $attribute->get(AdyenPayment::ADYEN_STORED_METHOD_ID) - ? $attribute->get(AdyenPayment::ADYEN_STORED_METHOD_ID) - : $attribute->get(AdyenPayment::ADYEN_CODE); + private function provideEnrichedPaymentMeans( + PaymentMeanCollection $paymentMeans, + PaymentMethodCollection $adyenPaymentMethods + ): array { + $enricher = $this->paymentMethodEnricher; - $paymentMethod = $adyenPaymentMethods->fetchByIdentifierOrStoredId($identifierOrStoredId); + return $paymentMeans + ->filterExcludeHidden() + ->map(static function(PaymentMean $paymentMean) use ($adyenPaymentMethods, $enricher): ?PaymentMean { + if (!$paymentMean->getSource()->equals(SourceType::adyen())) { + return $paymentMean; + } + $paymentMethod = $adyenPaymentMethods->fetchByPaymentMean($paymentMean); if (null === $paymentMethod) { return null; } - return PaymentMean::createFromShopwareArray(($enricher)($shopwareMethod->getRaw(), $paymentMethod)); + return PaymentMean::createFromShopwareArray(($enricher)($paymentMean->getRaw(), $paymentMethod)); + }); + } + + 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 { + return PaymentMean::createFromShopwareArray( + ($enricher)($umbrellaPaymentMean->getRaw(), $paymentMethod) + ); } - )); + ); } } diff --git a/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php b/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php new file mode 100644 index 00000000..0b8a06f5 --- /dev/null +++ b/Components/Adyen/PaymentMethod/StoredPaymentMeanProvider.php @@ -0,0 +1,51 @@ +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; + } + + $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( + PaymentMeanCollection::createFromShopwareArray($this->fetchUmbrellaMethod()) + ); + + return $enrichedPaymentMeans->fetchByUmbrellaStoredMethodId($registerPayment); + } + + private function fetchUmbrellaMethod(): array + { + $queryBuilder = $this->connection->createQueryBuilder(); + + 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 new file mode 100644 index 00000000..e7ade33a --- /dev/null +++ b/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderInterface.php @@ -0,0 +1,13 @@ +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/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 @@ + Shopware()->Shop()->getCurrency()->getFactor(), ]); - return $this->db->lastInsertId(); + return (int) $this->db->lastInsertId(); } /** diff --git a/Components/Manager/UserPreferenceManager.php b/Components/Manager/UserPreferenceManager.php new file mode 100644 index 00000000..eb79968e --- /dev/null +++ b/Components/Manager/UserPreferenceManager.php @@ -0,0 +1,24 @@ +modelManager = $modelManager; + } + + public function save(UserPreference $userPreference): void + { + $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..fe8e5262 --- /dev/null +++ b/Components/Manager/UserPreferenceManagerInterface.php @@ -0,0 +1,12 @@ +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
" : '' )); } } 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 45edbc9c..21b67139 100644 --- a/Enricher/Payment/PaymentMethodEnricher.php +++ b/Enricher/Payment/PaymentMethodEnricher.php @@ -5,6 +5,7 @@ namespace AdyenPayment\Enricher\Payment; use AdyenPayment\Components\Adyen\PaymentMethod\ImageLogoProviderInterface; +use AdyenPayment\Models\Enum\PaymentMethod\SourceType; use AdyenPayment\Models\Payment\PaymentMethod; use Shopware_Components_Snippet_Manager; @@ -25,16 +26,18 @@ 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(), - ]); + ], + $this->enrichStoredPaymentMethodData($shopwareMethod, $paymentMethod) + ); } - private function enrichDescription(PaymentMethod $adyenMethod): string + private function enrichAdditionalDescription(PaymentMethod $adyenMethod): string { $description = $this->snippets ->getNamespace('adyen/method/description') @@ -53,4 +56,22 @@ private function enrichDescription(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(), + ]; + } } 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 @@ +source; } + public function isHidden(): bool + { + return (bool) ($this->raw['hide'] ?? false); + } + public function getAttribute(): Attribute { return $this->raw['attribute'] ?? new Attribute(); @@ -59,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/Models/Payment/PaymentMethod.php b/Models/Payment/PaymentMethod.php index 18b9ced6..1ad42ccf 100644 --- a/Models/Payment/PaymentMethod.php +++ b/Models/Payment/PaymentMethod.php @@ -35,12 +35,12 @@ public static function fromRaw(array $data): self return $new; } - public function withCode(string $code): self + public function withCode(string $name): self { $new = clone $this; $new->code = mb_strtolower(sprintf('%s_%s', $this->type->type(), - Sanitize::removeNonWord($code) + Sanitize::removeNonWord($name) )); return $new; diff --git a/Models/PaymentInfo.php b/Models/PaymentInfo.php index a5acf094..5b6903ff 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 (string) $this->storedMethodId; + } + + public function setStoredMethodId(string $storedMethodId): self + { + $this->storedMethodId = $storedMethodId; + + return $this; + } } diff --git a/Models/UserPreference.php b/Models/UserPreference.php new file mode 100644 index 00000000..92ca3859 --- /dev/null +++ b/Models/UserPreference.php @@ -0,0 +1,81 @@ +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 (string) $this->storedMethodId; + } + + public function setStoredMethodId(?string $storedMethodId): self + { + $this->storedMethodId = $storedMethodId; + + return $this; + } + + public function mapToView(): array + { + return [ + 'id' => $this->getId(), + 'userId' => $this->getUserId(), + 'storedMethodId' => $this->getStoredMethodId(), + ]; + } +} diff --git a/Resources/frontend/js/jquery.adyen-payment-selection.js b/Resources/frontend/js/jquery.adyen-payment-selection.js index 83964cf1..f76f1102 100644 --- a/Resources/frontend/js/jquery.adyen-payment-selection.js +++ b/Resources/frontend/js/jquery.adyen-payment-selection.js @@ -122,10 +122,19 @@ }, onPaymentFormSubmit: function (e) { var me = this; - if ($(me.opts.paymentMethodFormSubmitSelector).hasClass('is--disabled')) { + var $formSubmit = $(me.opts.paymentMethodFormSubmitSelector); + if ($formSubmit.hasClass('is--disabled')) { e.preventDefault(); return false; } + var $paymentElement = $('#' + me.selectedPaymentElementId)[0]; + var paymentMethod = this.getPaymentMethodById($paymentElement.value); + if(paymentMethod.isStoredPayment){ + $formSubmit.append( + $('') + ); + } + $paymentElement.value = paymentMethod.id; }, isPaymentElement: function (elementId) { return $('#' + elementId).parents(this.opts.paymentMethodSelector).length > 0; @@ -142,7 +151,10 @@ } me.selectedPaymentElementId = selectedPaymentElementId; - me.selectedPaymentId = $(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) { @@ -234,8 +246,10 @@ getPaymentMethodById: function (id) { var me = this; - return me.opts.enrichedPaymentMethods.filter(function(enrichedPaymentMethod) { - 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] || {}; }, /** @@ -503,10 +517,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 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/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/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/providers.xml b/Resources/services/providers.xml index e02f5105..5c7267d2 100644 --- a/Resources/services/providers.xml +++ b/Resources/services/providers.xml @@ -8,6 +8,10 @@ + + + + diff --git a/Resources/services/shopware.xml b/Resources/services/shopware.xml index 7e903c46..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 d18f2cd6..a05c526f 100644 --- a/Resources/services/subscribers.xml +++ b/Resources/services/subscribers.xml @@ -33,6 +33,9 @@ %adyen_payment.plugin_dir% + + + @@ -50,6 +53,11 @@ + + + + + @@ -87,11 +95,34 @@ - + + + + + + + + + + + + + + + + service('models').getRepository('AdyenPayment\\Models\\UserPreference') + + + + + + service('models').getRepository('AdyenPayment\\Models\\UserPreference') + + diff --git a/Resources/views/frontend/checkout/change_payment.tpl b/Resources/views/frontend/checkout/change_payment.tpl index bf0d77a7..84a8423b 100644 --- a/Resources/views/frontend/checkout/change_payment.tpl +++ b/Resources/views/frontend/checkout/change_payment.tpl @@ -7,6 +7,7 @@ {assign var="storedPaymentMethods" value=[]} {foreach $sPayments as $paymentMethod} {if 'isStoredPayment'|array_key_exists:$paymentMethod && true === $paymentMethod.isStoredPayment} + {append var="paymentMethod" value=$paymentMethod.stored_method_umbrella_id index='id'} {$storedPaymentMethods[] = $paymentMethod} {else} {$paymentMethods[] = $paymentMethod} diff --git a/Resources/views/frontend/register/payment_fieldset.tpl b/Resources/views/frontend/register/payment_fieldset.tpl new file mode 100644 index 00000000..b9667b9c --- /dev/null +++ b/Resources/views/frontend/register/payment_fieldset.tpl @@ -0,0 +1,18 @@ +{extends file='parent:frontend/register/payment_fieldset.tpl'} + +{block name="frontend_register_payment_fieldset_input_radio"} + {assign var='isStoredPayment' value=('isStoredPayment'|array_key_exists:$payment_mean && true === $payment_mean.isStoredPayment)} + {if $isStoredPayment} + {append var="payment_mean" value=($payment_mean.stored_method_umbrella_id) index='id'} + {/if} + +{/block} 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->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/AddStoredMethodIdOnOrderSubscriber.php b/Subscriber/AddStoredMethodIdOnOrderSubscriber.php new file mode 100644 index 00000000..70c39c92 --- /dev/null +++ b/Subscriber/AddStoredMethodIdOnOrderSubscriber.php @@ -0,0 +1,55 @@ +modelManager = $modelManager; + $this->paymentInfoRepository = $this->modelManager->getRepository(PaymentInfo::class); + $this->session = $session; + } + + public static function getSubscribedEvents() + { + return ['Shopware_Modules_Order_SaveOrder_ProcessDetails' => 'persistPaymentInfoStoredMethodId']; + } + + public function persistPaymentInfoStoredMethodId(Enlight_Event_EventArgs $args) + { + $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(); + } + + /** @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(); + } +} diff --git a/Subscriber/Backend/HideStoredPaymentsSubscriber.php b/Subscriber/Backend/HideStoredPaymentsSubscriber.php new file mode 100644 index 00000000..9459e779 --- /dev/null +++ b/Subscriber/Backend/HideStoredPaymentsSubscriber.php @@ -0,0 +1,53 @@ + '__invoke', + 'Enlight_Controller_Action_PostDispatchSecure_Backend_Shipping' => '__invoke', + ]; + } + + public function __invoke(\Enlight_Controller_ActionEventArgs $args): void + { + if (!$this->isSuccessGetPaymentAction($args)) { + return; + } + + $data = $args->getSubject()->View()->getAssign('data') ?? []; + if (!count($data)) { + return; + } + + $data = PaymentMeanCollection::createFromShopwareArray($data) + ->filterExcludeHidden() + ->toShopwareArray(); + + $args->getSubject()->View()->assign('data', array_values($data)); + } + + 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; + } + + return true; + } +} diff --git a/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php new file mode 100644 index 00000000..82889f3c --- /dev/null +++ b/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriber.php @@ -0,0 +1,78 @@ +session = $session; + $this->paymentMeansProvider = $paymentMeansProvider; + } + + 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 = $args->getRequest()->getActionName(); + $isShippingPaymentView = 'shippingPayment' === $actionName && !$args->getRequest()->getParam('isXHR'); + if (!$isShippingPaymentView) { + 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) { + $preselectedPaymentId = $userData['additional']['payment']['id'] ?? null; + if (null === $preselectedPaymentId) { + return; + } + + $umbrellaPayment = $enrichedPaymentMeans->fetchStoredMethodUmbrellaPaymentMean(); + if (null === $umbrellaPayment) { + // 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) { + 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; + } + + if (null === $storedMethodId) { + return; + } + + $paymentMean = $enrichedPaymentMeans->fetchByStoredMethodId($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->getValue('stored_method_umbrella_id')]); + } +} diff --git a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php index a050a9e8..eb157adc 100644 --- a/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php +++ b/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriber.php @@ -4,18 +4,27 @@ namespace AdyenPayment\Subscriber\Checkout; +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) - { + public function __construct( + EnrichedPaymentMeanProviderInterface $enrichedPaymentMeanProvider, + PaymentMeansProviderInterface $paymentMeansProvider, + Enlight_Components_Session_Namespace $session + ) { $this->enrichedPaymentMeanProvider = $enrichedPaymentMeanProvider; + $this->paymentMeansProvider = $paymentMeansProvider; + $this->session = $session; } public static function getSubscribedEvents(): array @@ -29,21 +38,30 @@ 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; } + $storedMethodId = $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); $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; + } + + $enrichedPaymentMeans = ($this->enrichedPaymentMeanProvider)( + PaymentMeanCollection::createFromShopwareArray(($this->paymentMeansProvider)()) ); - if (!$paymentMean->getId()) { + + $paymentMean = null === $storedMethodId + ? $enrichedPaymentMeans->fetchById((int) $paymentMeanId) + : $enrichedPaymentMeans->fetchByStoredMethodId($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/PersistStoredMethodIdSubscriber.php b/Subscriber/Checkout/PersistStoredMethodIdSubscriber.php new file mode 100644 index 00000000..6642a4bf --- /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 + { + $actionName = $args->getRequest()->getActionName(); + + $isShippingPaymentUpdate = 'shippingPayment' === $actionName && $args->getRequest()->getParam('isXHR'); + $isSaveShippingPayment = 'saveShippingPayment' === $actionName; + if (!$isShippingPaymentUpdate && !$isSaveShippingPayment) { + return; + } + + $storedMethodId = $args->getRequest()->getParam(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID); + $this->session->set(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID, $storedMethodId); + } +} diff --git a/Subscriber/EnrichUserPreferenceSubscriber.php b/Subscriber/EnrichUserPreferenceSubscriber.php new file mode 100755 index 00000000..0840cba3 --- /dev/null +++ b/Subscriber/EnrichUserPreferenceSubscriber.php @@ -0,0 +1,49 @@ +session = $session; + $this->userPreferenceRepository = $userPreferenceRepository; + } + + public static function getSubscribedEvents(): array + { + 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 + { + $userId = $this->session->get('sUserId'); + if (null === $userId) { + return; + } + + /** @var UserPreference $userPreference */ + $userPreference = $this->userPreferenceRepository->findOneBy(['userId' => $userId]); + if (null === $userPreference) { + return; + } + + $args->getSubject()->View()->assign('adyenUserPreference', $userPreference->mapToView()); + } +} 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" 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/plugin.xml b/plugin.xml index 1117f3f8..a52fa3ea 100644 --- a/plugin.xml +++ b/plugin.xml @@ -4,7 +4,7 @@ - 3.3.0 + 3.4.0 Adyen Adyen https://adyen.com @@ -289,4 +289,20 @@ 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 + + + + + Enable Adyen's stored payment methods feature + + + Enable Adyen's stored payment methods feature + + 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 diff --git a/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php new file mode 100644 index 00000000..99ea9bb0 --- /dev/null +++ b/tests/Unit/Collection/Payment/PaymentMeanCollectionTest.php @@ -0,0 +1,183 @@ +collection = new PaymentMeanCollection(); + } + + /** @test */ + public function it_implements_iterable(): void + { + self::assertInstanceOf(\IteratorAggregate::class, $this->collection); + } + + /** @test */ + public function it_can_count(): void + { + self::assertInstanceOf(\Countable::class, $this->collection); + self::assertCount(0, $this->collection); + } + + /** @test */ + public function it_can_map_with_a_callback(): void + { + $filteredSource = SourceType::adyen(); + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => $filteredSource->getType()], + ]); + + $result = $collection->map(static fn(PaymentMean $payment) => ['mapped']); + + self::assertEquals([['mapped']], $result); + } + + /** @test */ + public function it_can_filter_by_source(): void + { + $filteredSource = SourceType::adyen(); + + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['id' => $expected = 123, 'source' => $filteredSource->getType()], + ['id' => 456, 'source' => '1'], + ]); + + $result = $collection->filterBySource($filteredSource); + + self::assertInstanceOf(PaymentMeanCollection::class, $result); + self::assertCount(1, $result); + self::assertEquals($expected, iterator_to_array($result)[0]->getId()); + } + + /** @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(); + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['id' => 123, 'source' => $filteredSource->getType(), 'hide' => true], + ['id' => $expected = 345, 'source' => $filteredSource->getType()], + ]); + + $result = $collection->filterExcludeHidden(); + + 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 + { + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => SourceType::adyen()->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 + { + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['source' => SourceType::adyen()->getType()], + ['source' => '1'], + ]); + + $result = $collection->fetchStoredMethodUmbrellaPaymentMean(); + + self::assertNull($result); + } + + /** @test */ + public function it_can_fetch_a_payment_by_stored_method_id(): void + { + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['id' => 123, 'source' => SourceType::adyen()->getType()], + ['id' => $expected = 456, 'source' => '1', 'stored_method_id' => $paymentMeanId = 'test123'], + ]); + + $result = $collection->fetchByStoredMethodId($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_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 + { + $filteredSource = SourceType::adyen(); + $collection = PaymentMeanCollection::createFromShopwareArray([ + ['id' => $paymentMeanId = 123, 'source' => $filteredSource->getType()], + ['id' => '456', 'source' => '1'], + ]); + + $result = $collection->fetchById($paymentMeanId); + + self::assertInstanceOf(PaymentMean::class, $result); + self::assertEquals($paymentMeanId, $result->getId()); + } + + /** @test */ + public function it_returns_collection_in_shopware_array_format(): 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); + } +} diff --git a/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php new file mode 100644 index 00000000..eaac913a --- /dev/null +++ b/tests/Unit/Collection/Payment/PaymentMethodCollectionTest.php @@ -0,0 +1,150 @@ + [['type' => 'someType']]]); + + self::assertInstanceOf(\Countable::class, $result); + self::assertCount(1, $result); + } + + /** @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_can_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_map_adyen_payment_methods(): void + { + $expectedMethod = PaymentMethod::fromRaw($paymentMethodData = ['type' => '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_enrich_with_import_locale(): void + { + $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($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'); + $paymentMean = PaymentMean::createFromShopwareArray([ + '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]); + $collection = new PaymentMethodCollection($testPayment, $expectedPayment); + + $result = $collection->fetchByPaymentMean($paymentMean); + + self::assertSame($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); + } +} diff --git a/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php new file mode 100644 index 00000000..3405c4b4 --- /dev/null +++ b/tests/Unit/Components/Adyen/PaymentMethod/EnrichedPaymentMeanProviderTest.php @@ -0,0 +1,296 @@ +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_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 + { + $adyenIdentifier = sprintf('%s_%s', $adyenType = 'non', $adyenName = 'adyen'); + $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, + ]), + ]), + ); + + // 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_and_removes_payment_means_without_attribute(): void + { + $paymentMeans = new PaymentMeanCollection( + $paymentMeanOne = PaymentMean::createFromShopwareArray([ + 'id' => 19, + 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, + 'source' => SourceType::shopwareDefault()->getType(), + ]), + $paymentMeanTwo = 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(1, $result); + $this->assertEquals($paymentMeanOne, iterator_to_array($result)[0]); + } + + /** @test */ + public function it_does_not_enrich_payment_means_with_attribute_null_values(): void + { + $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, + ]), + ]), + ); + + $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, + 'name' => AdyenPayment::ADYEN_STORED_PAYMENT_UMBRELLA_CODE, + 'source' => SourceType::adyen()->getType(), + 'attribute' => new Attribute([ + 'adyen_type' => 'non_matching_adyen_identifier', + ]), + ]), + ); + + $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, + ]), + ]), + $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($storedRaw = [ + 'id' => $storedMethodId = 'adyen-stored-payment-method-id', + 'type' => $schemaType = '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, + ]); + + $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(2, $result); + $this->assertEquals($rawEnriched, iterator_to_array($result)[0]->getRaw()); + $this->assertEquals($storedRawEnriched, iterator_to_array($result)[1]->getRaw()); + } +} diff --git a/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php b/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php new file mode 100644 index 00000000..8043db3e --- /dev/null +++ b/tests/Unit/Components/Adyen/PaymentMethod/StoredPaymentMeanProviderTest.php @@ -0,0 +1,82 @@ +enrichedPaymentMeanProvider = $this->prophesize(EnrichedPaymentMeanProviderInterface::class); + $this->connection = $this->prophesize(Connection::class); + + $this->storedPaymentMeanProvider = new StoredPaymentMeanProvider( + $this->enrichedPaymentMeanProvider->reveal(), + $this->connection->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); + $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([]); + + $queryBuilder->execute()->willReturn($driverResultStatement->reveal()); + $this->connection->createQueryBuilder()->willReturn($queryBuilder->reveal()); + + $result = $this->storedPaymentMeanProvider->fromRequest($request->reveal()); + + self::assertNull($result); + } +} 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); + } +} diff --git a/tests/Unit/Components/Manager/UserPreferenceManagerTest.php b/tests/Unit/Components/Manager/UserPreferenceManagerTest.php new file mode 100644 index 00000000..4d401d90 --- /dev/null +++ b/tests/Unit/Components/Manager/UserPreferenceManagerTest.php @@ -0,0 +1,50 @@ +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_save_a_record(): void + { + $userPreference = new UserPreference(); + $userPreference->setUserId(1234); + $userPreference->setStoredMethodId('expected-method-id'); + + $this->modelManager->persist($userPreference)->shouldBeCalled(); + $this->modelManager->flush($userPreference)->shouldBeCalled(); + + $this->userPreferenceManager->save($userPreference); + } +} diff --git a/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php b/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php new file mode 100644 index 00000000..d46adb1d --- /dev/null +++ b/tests/Unit/Enricher/Payment/PaymentMethodEnricherTest.php @@ -0,0 +1,115 @@ +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(), + ]; + + self::assertEquals($expected, $result); + } +} 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 @@ + '1425514', 'attribute' => new Attribute([ 'adyen_type' => 'adyen-type', - 'adyen_stored_method_id' => 'stored payment method id', ]), 'enriched' => true, 'adyenType' => 'adyen-type', + 'hide' => true, ]); } @@ -42,6 +42,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 { @@ -51,10 +57,10 @@ 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', + 'hide' => true, ], $this->paymentMean->getRaw()); } @@ -94,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()); } @@ -111,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 { 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/Backend/HideStoredPaymentsSubscriberTest.php b/tests/Unit/Subscriber/Backend/HideStoredPaymentsSubscriberTest.php new file mode 100644 index 00000000..b825f572 --- /dev/null +++ b/tests/Unit/Subscriber/Backend/HideStoredPaymentsSubscriberTest.php @@ -0,0 +1,119 @@ +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/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php new file mode 100644 index 00000000..f6a4bcf6 --- /dev/null +++ b/tests/Unit/Subscriber/Checkout/EnrichUmbrellaPaymentMeanSubscriberTest.php @@ -0,0 +1,174 @@ +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); + self::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); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + 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); + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_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([]); + + $this->subscriber->__invoke($eventArgs); + self::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->paymentMeansProvider->__invoke()->willReturn([]); + $this->session->get(AdyenPayment::SESSION_ADYEN_STORED_METHOD_ID)->willReturn($storedMethodId = 'method-id'); + $this->subscriber->__invoke($eventArgs); + self::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], + ]; + + self::assertEquals($expected, $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], + ]; + + self::assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + } +} diff --git a/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php b/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php new file mode 100644 index 00000000..66ce633a --- /dev/null +++ b/tests/Unit/Subscriber/Checkout/EnrichUserAdditionalPaymentSubscriberTest.php @@ -0,0 +1,168 @@ +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); + self::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); + self::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); + + self::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); + + self::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]], + ]; + + self::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]], + ]; + + self::assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + } +} diff --git a/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php b/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php new file mode 100644 index 00000000..c55b1386 --- /dev/null +++ b/tests/Unit/Subscriber/Checkout/PersistStoredMehtodIdSubscriberTest.php @@ -0,0 +1,90 @@ +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->session->set(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($eventArgs); + } + + /** @test */ + public function it_does_nothing_on_shipping_payment_non_xhr_request(): void + { + $eventArgs = $this->buildEventArgs('shippingPayment', $viewData = []); + $eventArgs->getRequest()->setParam('isXHR', false); + + $this->session->set(Argument::cetera())->shouldNotBeCalled(); + + $this->subscriber->__invoke($eventArgs); + } + + /** @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); + } +} diff --git a/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php new file mode 100644 index 00000000..654c2993 --- /dev/null +++ b/tests/Unit/Subscriber/EnrichUserPreferenceSubscriberTest.php @@ -0,0 +1,105 @@ +session = $this->prophesize(Enlight_Components_Session_Namespace::class); + $this->userPreferenceRepository = $this->prophesize(EntityRepository::class); + $this->subscriber = new EnrichUserPreferenceSubscriber( + $this->session->reveal(), + $this->userPreferenceRepository->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); + + self::assertEquals($viewData, $eventArgs->getSubject()->View()->getAssign()); + } + + /** @test */ + public function it_does_nothing_on_missing_user_preference(): void + { + $this->session->get('sUserId')->willReturn($userId = 1234); + $this->userPreferenceRepository->findOneBy(['userId' => $userId])->willReturn(null); + + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); + + $this->subscriber->__invoke($eventArgs); + + self::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'); + $this->userPreferenceRepository->findOneBy(['userId' => $userId])->willReturn($userPreference); + + $eventArgs = $this->buildEventArgs('', $viewData = ['data' => 'view-data']); + + $this->subscriber->__invoke($eventArgs); + + $expected = [ + 'data' => 'view-data', + 'adyenUserPreference' => [ + 'id' => $id, + 'userId' => $userId, + 'storedMethodId' => $storedMethodId, + ], + ]; + self::assertEquals($expected, $eventArgs->getSubject()->View()->getAssign()); + } +} diff --git a/tests/Unit/Subscriber/SubscriberTestCase.php b/tests/Unit/Subscriber/SubscriberTestCase.php new file mode 100644 index 00000000..4a650e36 --- /dev/null +++ b/tests/Unit/Subscriber/SubscriberTestCase.php @@ -0,0 +1,42 @@ +setActionName($actionName); + $request->setMethod($requestMethod); + + return new \Enlight_Controller_ActionEventArgs([ + 'subject' => $this->buildSubject($viewData), + 'request' => $request, + '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; + } +}