From 52d408794e64cb0a5b0a696fa736e0d069204991 Mon Sep 17 00:00:00 2001 From: Marjan Date: Thu, 1 Feb 2024 18:04:57 +0100 Subject: [PATCH 01/40] Initial RC1 commit --- Api/Data/MagewireComponentInterface.php | 57 ++++ Api/Data/StoredCreditCardInterface.php | 96 +++++++ Api/ProcessingMetadataInterface.php | 20 ++ Block/PaymentMethod.php | 43 +++ Block/SavedCards.php | 58 ++++ Magewire/Checkout/CouponCode.php | 87 ++++++ Magewire/Checkout/Success.php | 125 +++++++++ .../Payment/Method/AdyenPaymentComponent.php | 179 ++++++++++++ Magewire/Payment/Method/ApplePay.php | 28 ++ Magewire/Payment/Method/CreditCard.php | 70 +++++ Magewire/Payment/Method/GooglePay.php | 28 ++ Magewire/Payment/Method/Paypal.php | 27 ++ Magewire/Payment/Method/SavedCards.php | 41 +++ .../ResetHandler/QuoteStatus.php | 39 +++ .../ResetHandler/ResetHandlerInterface.php | 14 + Model/CheckoutSession/ResetHandlerPool.php | 38 +++ Model/Component/MagewireComponent.php | 75 +++++ Model/Configuration.php | 56 ++++ Model/CreditCard/BrandsManager.php | 47 ++++ Model/CreditCard/SavedCardsManager.php | 167 +++++++++++ Model/Data/StoredCreditCard.php | 129 +++++++++ Model/MethodList.php | 45 +++ Observer/HyvaCheckoutSessionReset.php | 31 +++ .../Magewire/Component/Resolver/Checkout.php | 60 ++++ Plugin/InitMethods.php | 176 ++++++++++++ ViewModel/SavedCards.php | 22 ++ composer.json | 18 ++ etc/di.xml | 26 ++ etc/frontend/di.xml | 10 + etc/frontend/events.xml | 13 + .../layout/checkout_onepage_success.xml | 19 ++ .../layout/hyva_checkout_components.xml | 54 ++++ .../layout/hyva_checkout_index_index.xml | 22 ++ .../checkout/payment/method-list.phtml | 90 ++++++ .../payment/method-list/saved-cards.phtml | 56 ++++ .../frontend/templates/checkout/success.phtml | 83 ++++++ .../templates/payment/init/init.phtml | 35 +++ .../adyen-applepay-method.phtml | 83 ++++++ .../method-renderer/adyen-cc-method.phtml | 76 +++++ .../adyen-cc-vault-method.phtml | 84 ++++++ .../adyen-googlepay-method.phtml | 82 ++++++ .../method-renderer/adyen-paypal-method.phtml | 80 ++++++ .../payment/model/adyen-payment-method.phtml | 263 ++++++++++++++++++ 43 files changed, 2852 insertions(+) create mode 100644 Api/Data/MagewireComponentInterface.php create mode 100644 Api/Data/StoredCreditCardInterface.php create mode 100644 Api/ProcessingMetadataInterface.php create mode 100644 Block/PaymentMethod.php create mode 100644 Block/SavedCards.php create mode 100644 Magewire/Checkout/CouponCode.php create mode 100644 Magewire/Checkout/Success.php create mode 100644 Magewire/Payment/Method/AdyenPaymentComponent.php create mode 100644 Magewire/Payment/Method/ApplePay.php create mode 100644 Magewire/Payment/Method/CreditCard.php create mode 100644 Magewire/Payment/Method/GooglePay.php create mode 100644 Magewire/Payment/Method/Paypal.php create mode 100644 Magewire/Payment/Method/SavedCards.php create mode 100644 Model/CheckoutSession/ResetHandler/QuoteStatus.php create mode 100644 Model/CheckoutSession/ResetHandler/ResetHandlerInterface.php create mode 100644 Model/CheckoutSession/ResetHandlerPool.php create mode 100644 Model/Component/MagewireComponent.php create mode 100644 Model/Configuration.php create mode 100644 Model/CreditCard/BrandsManager.php create mode 100644 Model/CreditCard/SavedCardsManager.php create mode 100644 Model/Data/StoredCreditCard.php create mode 100644 Model/MethodList.php create mode 100644 Observer/HyvaCheckoutSessionReset.php create mode 100644 Plugin/HyvaCheckout/Model/Magewire/Component/Resolver/Checkout.php create mode 100644 Plugin/InitMethods.php create mode 100644 ViewModel/SavedCards.php create mode 100644 composer.json create mode 100644 etc/di.xml create mode 100644 etc/frontend/di.xml create mode 100644 etc/frontend/events.xml create mode 100644 view/frontend/layout/checkout_onepage_success.xml create mode 100644 view/frontend/layout/hyva_checkout_components.xml create mode 100644 view/frontend/layout/hyva_checkout_index_index.xml create mode 100644 view/frontend/templates/checkout/payment/method-list.phtml create mode 100644 view/frontend/templates/checkout/payment/method-list/saved-cards.phtml create mode 100644 view/frontend/templates/checkout/success.phtml create mode 100644 view/frontend/templates/payment/init/init.phtml create mode 100644 view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml create mode 100644 view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml create mode 100644 view/frontend/templates/payment/method-renderer/adyen-cc-vault-method.phtml create mode 100644 view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml create mode 100644 view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml create mode 100644 view/frontend/templates/payment/model/adyen-payment-method.phtml diff --git a/Api/Data/MagewireComponentInterface.php b/Api/Data/MagewireComponentInterface.php new file mode 100644 index 00000000..7966af0a --- /dev/null +++ b/Api/Data/MagewireComponentInterface.php @@ -0,0 +1,57 @@ +configuration = $configuration; + $this->checkoutSession = $checkoutSession; + } + + /** + * @return Configuration + */ + public function getConfiguration(): Configuration + { + return $this->configuration; + } + + public function getQuoteShippingAddress() + { + return json_encode($this->checkoutSession->getQuote()->getShippingAddress()->getData()); + } + + public function getQuoteBillingAddress() + { + return json_encode($this->checkoutSession->getQuote()->getBillingAddress()->getData()); + } +} diff --git a/Block/SavedCards.php b/Block/SavedCards.php new file mode 100644 index 00000000..e7fd04c5 --- /dev/null +++ b/Block/SavedCards.php @@ -0,0 +1,58 @@ +getLayout()->getBlock('checkout.payment.methods'); + + if ($paymentMethodsBlock + && $paymentMethodsBlock->getData(ProcessingMetadataInterface::BLOCK_PROPERTY_MAGEWIRE) + ) { + return $paymentMethodsBlock->getData(ProcessingMetadataInterface::BLOCK_PROPERTY_MAGEWIRE); + } + } catch (\Exception $exception) { + return null; + } + + return null; + } + + /** + * @param StoredCreditCardInterface $storedCreditCard + * @return Template|null + */ + public function getNewVaultBlock(StoredCreditCardInterface $storedCreditCard): ?Template + { + try { + return $this->getLayout()->createBlock(Template::class) + ->setNameInLayout($storedCreditCard->getLayoutId()) + ->setData(ProcessingMetadataInterface::BLOCK_PROPERTY_STORED_CARD, $storedCreditCard) + ->setData(ProcessingMetadataInterface::BLOCK_PROPERTY_MAGEWIRE, $this->getNewMagewireInstance()) + ->setTemplate('Adyen_Hyva::payment/method-renderer/adyen-cc-vault-method.phtml'); + } catch (\Exception $exception) { + return null; + } + } + + /** + * @return Component + */ + private function getNewMagewireInstance(): Component + { + return ObjectManager::getInstance()->create(SavedCardsWire::class); + } +} diff --git a/Magewire/Checkout/CouponCode.php b/Magewire/Checkout/CouponCode.php new file mode 100644 index 00000000..b4ab866b --- /dev/null +++ b/Magewire/Checkout/CouponCode.php @@ -0,0 +1,87 @@ +couponManagement = $couponManagement; + $this->sessionCheckout = $sessionCheckout; + } + + /** + * @throws NoSuchEntityException + */ + public function boot(): void + { + $couponCode = $this->couponManagement->get($this->sessionCheckout->getQuoteId()); + $this->couponCode = $couponCode ?? null; + } + + public function applyCouponCode() + { + try { + $quoteEntity = $this->sessionCheckout->getQuoteId(); + + if (empty($this->couponCode)) { + throw new LocalizedException( + __('No Coupon') + ); + } + if (! empty($this->couponManagement->get($quoteEntity))) { + throw new LocalizedException( + __('A coupon is already applied to the cart. Please remove it to apply another') + ); + } + + $this->couponManagement->set($quoteEntity, $this->couponCode); + $this->reset(['couponHits']); + } catch (LocalizedException $exception) { + $this->couponCode = null; + $this->couponHits++; + + return $this->dispatchWarningMessage($exception->getMessage()); + } + + $this->dispatchSuccessMessage('Your coupon was successfully applied.'); + $this->dispatchBrowserEvent('checkout:coupon:activate'); + $this->emit('coupon_code_applied'); + + return true; + } + + public function revokeCouponCode() + { + try { + if (empty($this->couponCode)) { + throw new LocalizedException(__('No Coupon')); + } + + $this->reset(); + $this->couponManagement->remove($this->sessionCheckout->getQuoteId()); + } catch (LocalizedException $exception) { + return $this->dispatchWarningMessage($exception->getMessage()); + } + + $this->dispatchSuccessMessage('Your coupon was successfully removed.'); + $this->dispatchBrowserEvent('checkout:coupon:deactivate'); + $this->emit('coupon_code_revoked'); + + return true; + } +} diff --git a/Magewire/Checkout/Success.php b/Magewire/Checkout/Success.php new file mode 100644 index 00000000..055faba2 --- /dev/null +++ b/Magewire/Checkout/Success.php @@ -0,0 +1,125 @@ +session = $session; + $this->adyenDonations = $adyenDonations; + $this->guestAdyenDonations = $guestAdyenDonations; + $this->orderFactory = $orderFactory; + $this->helperConfig = $helperConfig; + $this->storeManager = $storeManager; + $this->logger = $logger; + } + + /** + * @return bool + */ + public function userIsGuest(): string + { + try { + $customerId = $this->session->getQuote()->getCustomerId(); + + if ($customerId) { + return "customer"; + } + } catch (Exception $exception) { + return "guest"; + } + + return "guest"; + } + + public function showAdyenGiving(): bool + { + return $this->adyenGivingEnabled() && $this->hasDonationToken(); + } + + private function adyenGivingEnabled(): bool + { + return (bool) $this->helperConfig->adyenGivingEnabled($this->storeManager->getStore()->getId()); + } + + private function hasDonationToken(): bool + { + return $this->getDonationToken() && 'null' !== $this->getDonationToken(); + } + + private function getDonationToken() + { + return json_encode($this->getOrder()->getPayment()->getAdditionalInformation('donationToken')); + } + + private function getOrder() + { + return $this->orderFactory->create()->load($this->session->getLastOrderId()); + } + + /** + * @return string + */ + public function getStateData(): string + { + return json_encode($this->session->getStateData()) ?? '{}'; + } + + /** + * @param int $orderId + * @param array $payload + */ + public function donate(int $orderId, array $payload) + { + try { + $this->adyenDonations->donate($orderId, json_encode($payload)); + $this->donationStatus = true; + } catch (\Exception $exception) { + $this->logger->error($exception->getMessage()); + $this->donationStatus = false; + } + } + + /** + * @param string $maskedCartId + * @param array $payload + */ + public function donateGuest(string $maskedCartId, array $payload) + { + try { + $this->guestAdyenDonations->donate($maskedCartId, json_encode($payload)); + $this->donationStatus = true; + } catch (\Exception $exception) { + $this->logger->error($exception->getMessage()); + $this->donationStatus = false; + } + } +} diff --git a/Magewire/Payment/Method/AdyenPaymentComponent.php b/Magewire/Payment/Method/AdyenPaymentComponent.php new file mode 100644 index 00000000..4867f4f1 --- /dev/null +++ b/Magewire/Payment/Method/AdyenPaymentComponent.php @@ -0,0 +1,179 @@ +checkoutStateDataValidator = $checkoutStateDataValidator; + $this->configuration = $configuration; + $this->session = $session; + $this->stateData = $stateData; + $this->paymentMethods = $paymentMethods; + $this->paymentInformationManagement = $paymentInformationManagement; + $this->adyenOrderPaymentStatus = $adyenOrderPaymentStatus; + $this->adyenPaymentsDetails = $adyenPaymentsDetails; + } + + /** + * @return string + */ + abstract function getMethodCode(): string; + + /** + * @return Configuration + */ + public function getConfiguration(): Configuration + { + return $this->configuration; + } + + /** + * @return bool + */ + public function userIsGuest(): bool + { + try { + $customerId = $this->session->getQuote()->getCustomerId(); + + if ($customerId) { + return false; + } + } catch (Exception $exception) { + return true; + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function mount(): void + { + try { + $this->processIsShippingRequired(); + $this->paymentResponse = $this->paymentMethods->getData((int) $this->session->getQuoteId()); + } catch (Exception $exception) { + $this->paymentResponse = '{}'; + } + } + + /** + * @param array $data + * @throws Exception + */ + public function placeOrder(array $data) { + try { + $quoteId = $this->session->getQuoteId(); + $payment = $this->session->getQuote()->getPayment(); + $stateDataReceived = $this->collectValidatedStateData($data); + //Temporary (per request) storage of state data + $this->stateData->setStateData($stateDataReceived, (int) $quoteId); + $orderId = $this->paymentInformationManagement->savePaymentInformationAndPlaceOrder( + $quoteId, + $payment + ); + $this->orderId = $orderId; + $this->paymentStatus = $this->adyenOrderPaymentStatus->getOrderPaymentStatus($this->orderId); + $this->session->setStateData($stateDataReceived); + } catch (Exception $exception) { + $this->paymentStatus = json_encode(['isRefused' => true]); + } + } + + /** + * @param array $data + */ + public function collectPaymentDetails(array $data) + { + try { + $this->paymentDetails = $this->adyenPaymentsDetails->initiate(json_encode($data), $this->session->getLastRealOrder()->getId()); + } catch (Exception $exception) { + $this->paymentDetails = json_encode(['isRefused' => true]); + } + } + + /** + * @param array $data + * @return array + */ + protected function collectValidatedStateData(array $data): array + { + if (isset($data[ProcessingMetadataInterface::POST_KEY_STATE_DATA])) { + return $this->checkoutStateDataValidator->getValidatedAdditionalData( + $data[ProcessingMetadataInterface::POST_KEY_STATE_DATA] + ); + } + + return []; + } + + public function processIsShippingRequired() + { + if ($this->session->getQuote()->isVirtual()) { + $this->requiresShipping = false; + } else { + if ($shippingMethod = $this->getCurrentShippingMethod()) { + $this->requiresShipping = false; + } else { + $this->requiresShipping = true; + } + } + } + + /** + * @return string|null + */ + private function getCurrentShippingMethod(): ?string + { + try { + $shippingAddress = $this->session->getQuote()->getShippingAddress(); + + if ($shippingAddress && $shippingAddress->getShippingMethod()) { + return $shippingAddress->getShippingMethod(); + } + } catch (\Exception $exception) { + return null; + } + + return null; + } +} diff --git a/Magewire/Payment/Method/ApplePay.php b/Magewire/Payment/Method/ApplePay.php new file mode 100644 index 00000000..f5b61910 --- /dev/null +++ b/Magewire/Payment/Method/ApplePay.php @@ -0,0 +1,28 @@ +createBlocking(); + } +} diff --git a/Magewire/Payment/Method/CreditCard.php b/Magewire/Payment/Method/CreditCard.php new file mode 100644 index 00000000..cb9de0df --- /dev/null +++ b/Magewire/Payment/Method/CreditCard.php @@ -0,0 +1,70 @@ +brandsManager = $brandsManager; + } + + /** + * {@inheritDoc} + */ + public function getMethodCode(): string + { + return ProcessingMetadataInterface::METHOD_CC; + } + + /** + * {@inheritDoc} + */ + public function evaluateCompletion(EvaluationResultFactory $resultFactory): EvaluationResultInterface + { + return $resultFactory->createSuccess(); + } + + /** + * @return string + */ + public function getBrands(): string + { + return $this->brandsManager->getBrands(); + } +} diff --git a/Magewire/Payment/Method/GooglePay.php b/Magewire/Payment/Method/GooglePay.php new file mode 100644 index 00000000..718af444 --- /dev/null +++ b/Magewire/Payment/Method/GooglePay.php @@ -0,0 +1,28 @@ +createBlocking(); + } +} diff --git a/Magewire/Payment/Method/Paypal.php b/Magewire/Payment/Method/Paypal.php new file mode 100644 index 00000000..6c8dbc8e --- /dev/null +++ b/Magewire/Payment/Method/Paypal.php @@ -0,0 +1,27 @@ +createBlocking(); + } +} diff --git a/Magewire/Payment/Method/SavedCards.php b/Magewire/Payment/Method/SavedCards.php new file mode 100644 index 00000000..e648573a --- /dev/null +++ b/Magewire/Payment/Method/SavedCards.php @@ -0,0 +1,41 @@ +createSuccess(); + } + + /** + * @inheritDoc + */ + public function placeOrder(array $data): void + { + if (isset($data[ProcessingMetadataInterface::POST_KEY_PUBLIC_HASH])) { + $this->session->setSavedCardPublicHash($data[ProcessingMetadataInterface::POST_KEY_PUBLIC_HASH]); + } + + $quotePayment = $this->session->getQuote()->getPayment(); + $quotePayment->setMethod($this->getMethodCode()); + + parent::placeOrder($data); + } +} diff --git a/Model/CheckoutSession/ResetHandler/QuoteStatus.php b/Model/CheckoutSession/ResetHandler/QuoteStatus.php new file mode 100644 index 00000000..8e1f55c0 --- /dev/null +++ b/Model/CheckoutSession/ResetHandler/QuoteStatus.php @@ -0,0 +1,39 @@ +methodList = $methodList; + } + + /** + * @inheritDoc + */ + public function delayReset(CartInterface $cart): bool + { + if ($cart->getIsActive() + && in_array($cart->getPayment()->getMethod(), $this->methodList->collectAvailableMethods()) + ) { + return true; + } + + return false; + } +} diff --git a/Model/CheckoutSession/ResetHandler/ResetHandlerInterface.php b/Model/CheckoutSession/ResetHandler/ResetHandlerInterface.php new file mode 100644 index 00000000..e4f44fd3 --- /dev/null +++ b/Model/CheckoutSession/ResetHandler/ResetHandlerInterface.php @@ -0,0 +1,14 @@ +resetHandlers[] = $resetHandler; + } + } + } + + /** + * {@inheritDoc} + */ + public function delayReset(CartInterface $cart): bool + { + foreach ($this->resetHandlers as $resetHandler) { + if ($resetHandler->delayReset($cart)) { + return true; + } + } + + return false; + } +} diff --git a/Model/Component/MagewireComponent.php b/Model/Component/MagewireComponent.php new file mode 100644 index 00000000..f48ae758 --- /dev/null +++ b/Model/Component/MagewireComponent.php @@ -0,0 +1,75 @@ +setData(self::NAME, $name); + } + + /** + * @inheritDoc + */ + public function setMagewire(Component $component): MagewireComponentInterface + { + return $this->setData(self::MAGEWIRE, $component); + } + + /** + * @inheritDoc + */ + public function setStoredCard(StoredCreditCardInterface $storedCard): MagewireComponentInterface + { + return $this->setData(self::STORED_CARD, $storedCard); + } + + /** + * @inheritDoc + */ + public function setTemplate(string $template): MagewireComponentInterface + { + return $this->setData(self::TEMPLATE, $template); + } + + /** + * @inheritDoc + */ + public function getName(): ?string + { + return $this->getData(self::NAME); + } + + /** + * @inheritDoc + */ + public function getMagewire(): ?Component + { + return $this->getData(self::MAGEWIRE); + } + + /** + * @inheritDoc + */ + public function getTemplate(): ?string + { + return $this->getData(self::TEMPLATE); + } + + /** + * @inheritDoc + */ + public function getStoredCard(): ?StoredCreditCardInterface + { + return $this->getData(self::STORED_CARD); + } +} diff --git a/Model/Configuration.php b/Model/Configuration.php new file mode 100644 index 00000000..aad7f218 --- /dev/null +++ b/Model/Configuration.php @@ -0,0 +1,56 @@ +getConfig()['payment']) && + $paymentConfiguration = json_decode(json_encode($configProvider->getConfig()['payment'])) + ) { + $this->paymentConfiguration = $paymentConfiguration; + } + } + + /** + * @param string $path + * @return mixed + */ + public function getValue(string $path): mixed + { + $result = $this->paymentConfiguration; + $pathParts = explode('/', $path); + + if (is_array($pathParts)) { + foreach ($pathParts as $part) { + if (property_exists($result, $part)) { + $result = $result->$part; + } else { + return null; + } + } + + return $result; + } + + return null; + } + + /** + * @return bool + */ + public function isCCEnableStoreDetails(bool $userIsGuest): bool + { + if ($userIsGuest) { + return false; + } + + return $this->getValue('adyenCc/isCardRecurringEnabled'); + } +} diff --git a/Model/CreditCard/BrandsManager.php b/Model/CreditCard/BrandsManager.php new file mode 100644 index 00000000..36a3aa81 --- /dev/null +++ b/Model/CreditCard/BrandsManager.php @@ -0,0 +1,47 @@ +session = $session; + $this->adyenPaymentMethodManagement = $adyenPaymentMethodManagement; + } + + /** + * @return string + */ + public function getBrands(): string + { + try { + $paymentMethodsResponse = json_decode( + $this->adyenPaymentMethodManagement->getPaymentMethods( + $this->session->getQuoteId() + ), + true + ); + + if (isset($paymentMethodsResponse['paymentMethodsResponse']['paymentMethods'])) { + foreach ($paymentMethodsResponse['paymentMethodsResponse']['paymentMethods'] as $paymentMethod) { + if ($paymentMethod['type'] == 'scheme') { + return json_encode($paymentMethod['brands']); + } + } + } + } catch (\Exception $exception) { + return json_encode([]); + } + + return json_encode([]); + } +} diff --git a/Model/CreditCard/SavedCardsManager.php b/Model/CreditCard/SavedCardsManager.php new file mode 100644 index 00000000..c96d8131 --- /dev/null +++ b/Model/CreditCard/SavedCardsManager.php @@ -0,0 +1,167 @@ +paymentTokenManagement = $paymentTokenManagement; + $this->customerSession = $customerSession; + $this->checkoutSession = $checkoutSession; + $this->adyenVaultHelper = $adyenVaultHelper; + $this->storeManager = $storeManager; + $this->storedCreditCardFactory = $storedCreditCardFactory; + $this->magewireComponentInterfaceFactory = $magewireComponentInterfaceFactory; + } + + /** + * @param string $layoutId + * @return StoredCreditCardInterface|null + */ + public function getStoredCard(string $layoutId): ?StoredCreditCardInterface + { + if (!$this->savedCardsLoaded) { + $this->getStoredCards(); + } + + /** @var StoredCreditCardInterface $savedCard */ + foreach ($this->savedCards as $savedCard) { + if ($savedCard->getLayoutId() == $layoutId) { + return $savedCard; + } + } + + return null; + } + + /** + * @param string $name + * @return MagewireComponentInterface|null + */ + public function getMagewireComponent(string $name): ?MagewireComponentInterface + { + /** @var StoredCreditCardInterface $storedCard */ + + if (str_starts_with($name, ProcessingMetadataInterface::VAULT_LAYOUT_PREFIX) + && $storedCard = $this->getStoredCard($name) + ) { + /** @var MagewireComponentInterface $magewireComponent */ + $magewireComponent = $this->magewireComponentInterfaceFactory->create(); + $magewireComponent->setName($name) + ->setMagewire(ObjectManager::getInstance()->create(SavedCards::class)) + ->setTemplate('Adyen_Hyva::payment/method-renderer/adyen-cc-vault-method.phtml') + ->setStoredCard($storedCard); + + return $magewireComponent; + } + + return null; + } + + /** + * @return array + */ + public function getStoredCards(): array + { + if ($this->savedCardsLoaded) { + return $this->savedCards; + } + + $storeId = (int) $this->storeManager->getStore()->getId(); + $customerId = (int) $this->customerSession->getCustomerId(); + $vaultData = $this->paymentTokenManagement->getListByCustomerId($customerId); + $counter = 1; + + /** @var PaymentTokenInterface $vaultEntry */ + foreach ($vaultData as $vaultToken) { + if ($this->adyenVaultHelper->getPaymentMethodRecurringActive($vaultToken->getPaymentMethodCode(), $storeId) + && strpos((string)$vaultToken->getPaymentMethodCode(), 'adyen_') === 0 + ) { + if ($storedCardDataObject = $this->getStoredCardDataObject($vaultToken, $counter)) { + $this->savedCards[] = $storedCardDataObject; + $counter++; + } + } + } + + $this->savedCardsLoaded = true; + + return $this->savedCards; + } + + /** + * @param PaymentTokenInterface $vaultToken + * @param int $counter + * @return StoredCreditCardInterface|null + */ + private function getStoredCardDataObject(PaymentTokenInterface $vaultToken, int $counter): ?StoredCreditCardInterface + { + if ($vaultToken instanceof PaymentTokenInterface + && $vaultToken->getIsActive() + && $vaultToken->getIsVisible() + && $vaultToken->getCustomerId() == (int) $this->customerSession->getCustomerId() + ) { + $vaultTokenDetails = json_decode($vaultToken->getTokenDetails(), true); + + if (!isset($vaultTokenDetails['type']) + || !isset($vaultTokenDetails['maskedCC']) + || !isset($vaultTokenDetails['expirationDate']) + || !isset($vaultTokenDetails['tokenType']) + || $vaultTokenDetails['tokenType'] != AdyenVaultHelper::CARD_ON_FILE + ) { + return null; + } + + $expirationDate = $vaultTokenDetails['expirationDate']; + list($expirationMonth, $expirationYear) = explode('/', $expirationDate); + + /** @var StoredCreditCardInterface $storedCreditCard */ + $storedCreditCard = $this->storedCreditCardFactory->create(); + + $storedCreditCard->setGatewayToken($vaultToken->getGatewayToken()) + ->setPublicHash($vaultToken->getPublicHash()) + ->setType($vaultTokenDetails['type']) + ->setMaskedCc($vaultTokenDetails['maskedCC']) + ->setExpiryMonth($expirationMonth) + ->setExpiryYear(substr($expirationYear, -2)) + ->setLayoutId(ProcessingMetadataInterface::VAULT_LAYOUT_PREFIX . $counter); + + return $storedCreditCard; + } + + return null; + } +} diff --git a/Model/Data/StoredCreditCard.php b/Model/Data/StoredCreditCard.php new file mode 100644 index 00000000..138d5ce7 --- /dev/null +++ b/Model/Data/StoredCreditCard.php @@ -0,0 +1,129 @@ +setData(self::GATEWAY_TOKEN, $token); + } + + /** + * @inheritDoc + */ + public function setPublicHash(string $publicHash): StoredCreditCardInterface + { + return $this->setData(self::PUBLIC_HASH, $publicHash); + } + + /** + * @inheritDoc + */ + public function setType(string $type): StoredCreditCardInterface + { + return $this->setData(self::TYPE, $type); + } + + /** + * @inheritDoc + */ + public function setMaskedCc(string $maskedCc): StoredCreditCardInterface + { + return $this->setData(self::MASKED_CC, $maskedCc); + } + + /** + * @inheritDoc + */ + public function setExpiryMonth(string $expiryMonth): StoredCreditCardInterface + { + return $this->setData(self::EXPIRY_MONTH, $expiryMonth); + } + + /** + * @inheritDoc + */ + public function setExpiryYear(string $expiryYear): StoredCreditCardInterface + { + return $this->setData(self::EXPIRY_YEAR, $expiryYear); + } + + /** + * @inheritDoc + */ + public function setLayoutId(string $layoutId): StoredCreditCardInterface + { + return $this->setData(self::LAYOUT_ID, $layoutId); + } + + /** + * @inheritDoc + */ + public function getGatewayToken(): ?string + { + return $this->getData(self::GATEWAY_TOKEN); + } + + /** + * @inheritDoc + */ + public function getPublicHash(): ?string + { + return $this->getData(self::PUBLIC_HASH); + } + + /** + * @inheritDoc + */ + public function getType(): ?string + { + return $this->getData(self::TYPE); + } + + /** + * @inheritDoc + */ + public function getMaskedCc(): ?string + { + return $this->getData(self::MASKED_CC); + } + + /** + * @inheritDoc + */ + public function getExpiryMonth(): ?string + { + return $this->getData(self::EXPIRY_MONTH); + } + + /** + * @inheritDoc + */ + public function getExpiryYear(): ?string + { + return $this->getData(self::EXPIRY_YEAR); + } + + /** + * @inheritDoc + */ + public function getLayoutId(): string + { + return $this->getData(self::LAYOUT_ID); + } + + /** + * @inheritDoc + */ + public function getPublicLabel(): string + { + return $this->getType() . ' ' . __('ending with') . ' ' . $this->getMaskedCc(); + } +} diff --git a/Model/MethodList.php b/Model/MethodList.php new file mode 100644 index 00000000..faa9f0ff --- /dev/null +++ b/Model/MethodList.php @@ -0,0 +1,45 @@ +availableMethods = $availableMethods; + $this->savedCardsManager = $savedCardsManager; + } + + /** + * @return array + */ + public function collectAvailableMethods(): array + { + $storedCards = $this->getStoredCardsMethods(); + + return array_unique(array_merge($this->availableMethods, $storedCards)); + } + + /** + * @return array + */ + private function getStoredCardsMethods(): array + { + $result = []; + + /** @var StoredCreditCardInterface $storedCard */ + foreach ($this->savedCardsManager->getStoredCards() as $storedCard) { + $result[] = $storedCard->getLayoutId(); + } + + return $result; + } +} diff --git a/Observer/HyvaCheckoutSessionReset.php b/Observer/HyvaCheckoutSessionReset.php new file mode 100644 index 00000000..3204a30f --- /dev/null +++ b/Observer/HyvaCheckoutSessionReset.php @@ -0,0 +1,31 @@ +sessionCheckoutConfig = $sessionCheckoutConfig; + $this->resetHandlerPool = $resetHandlerPool; + } + + public function execute(Observer $observer): void + { + $quote = $observer->getData('quote'); + + if (!$this->resetHandlerPool->delayReset($quote)) { + $this->sessionCheckoutConfig->reset(); + } + } +} diff --git a/Plugin/HyvaCheckout/Model/Magewire/Component/Resolver/Checkout.php b/Plugin/HyvaCheckout/Model/Magewire/Component/Resolver/Checkout.php new file mode 100644 index 00000000..f5354ef1 --- /dev/null +++ b/Plugin/HyvaCheckout/Model/Magewire/Component/Resolver/Checkout.php @@ -0,0 +1,60 @@ +layout = $layout; + $this->savedCardsManager = $savedCardsManager; + } + + /** + * @param Subject $subject + * @param callable $proceed + * @param Page $page + * @param RequestInterface $request + * @return void + */ + public function aroundProcessComponentRequest(Subject $subject, callable $proceed, Page $page, RequestInterface $request) + { + $proceed($page, $request); + + try { + if (str_contains($request->getFingerprint('name'), ProcessingMetadataInterface::VAULT_LAYOUT_PREFIX) + && $page->getLayout()->getBlock($request->getFingerprint('name')) == null + ) { + if ($registeredMagewire = $this->savedCardsManager->getMagewireComponent($request->getFingerprint('name'))) { + $paymentBlock = $page->getLayout()->createBlock( + \Magento\Framework\View\Element\Template::class, + $registeredMagewire->getName(), + [ + 'data' => [ + ProcessingMetadataInterface::BLOCK_PROPERTY_MAGEWIRE => $registeredMagewire->getMagewire(), + ProcessingMetadataInterface::BLOCK_PROPERTY_STORED_CARD => $registeredMagewire->getStoredCard() + ] + ] + )->setData('area', 'frontend')->setTemplate($registeredMagewire->getTemplate()); + + $page->getLayout()->addBlock($paymentBlock); + } + } + } catch (\Exception $exception) { + ; + } + } +} diff --git a/Plugin/InitMethods.php b/Plugin/InitMethods.php new file mode 100644 index 00000000..e31ed51e --- /dev/null +++ b/Plugin/InitMethods.php @@ -0,0 +1,176 @@ +cartRepository = $cartRepository; + $this->methodList = $methodList; + $this->paymentMethods = $paymentMethods; + $this->savedCardsManager = $savedCardsManager; + } + + /** + * @param Subject $subject + * @param array $list + * @param $quoteId + * @return array + * @throws LocalizedException + */ + public function afterGetList(Subject $subject, array $list, $quoteId): array + { + try { + /** + * Filter out methods that are Adyen Based, but are not supported in Hyva checkout + */ + foreach ($list as $key => $method) { + if ($this->isMethodAdyenBased($method) && !$this->isMethodHyvaSupported($method)) { + unset($list[$key]); + } + } + + /** + * Filter out methods that are Adyen Based, but are not supported by Adyen configuration + */ + $configuredKeys = $this->collectConfiguredKeys((int) $quoteId); + + foreach ($list as $key => $method) { + if ($this->isMethodAdyenBased($method) && !$this->isMethodAvailable($method, $configuredKeys)) { + unset($list[$key]); + } + } + + /** + * Remove Apple Pay if the device would not support the method + */ + $list = $this->handleApplePay($list); + + /** + * Handle Stored Cards + */ + $storedCards = $this->savedCardsManager->getStoredCards(); + + if (empty($storedCards)) { + foreach ($list as $key => $method) { + if ($method->getCode() == ProcessingMetadataInterface::METHOD_SAVED_CC) { + unset($list[$key]); + } + } + } + + return $list; + } catch (Exception $exception) { + throw new LocalizedException(__('Cannot find active quote')); + } + + return []; + } + + + /** + * @param $method + * @return bool + */ + private function isMethodAdyenBased($method): bool + { + if (str_starts_with($method->getCode(), ProcessingMetadataInterface::METHOD_ADYEN_PREFIX)) { + return true; + } + + return false; + } + + /** + * @param $method + * @return bool + */ + private function isMethodHyvaSupported($method): bool + { + if (in_array($method->getCode(), $this->methodList->collectAvailableMethods())) { + return true; + } + + return false; + } + + /** + * @param $method + * @param $configuredKeys + * @return bool + */ + private function isMethodAvailable($method, $configuredKeys): bool + { + $methodCode = $this->collectMethodCodeWithoutPrefix($method->getCode()); + + return in_array($methodCode, $configuredKeys); + } + + private function collectMethodCodeWithoutPrefix($methodCode): string + { + if ($methodCode == ProcessingMetadataInterface::METHOD_CC) { + return 'card'; + } + + return substr( + $methodCode, + strpos($methodCode, ProcessingMetadataInterface::METHOD_ADYEN_PREFIX) + strlen(ProcessingMetadataInterface::METHOD_ADYEN_PREFIX) + ); + } + + /** + * @param int $quoteId + * @return array + */ + private function collectConfiguredKeys(int $quoteId): array + { + $paymentMethodsConfiguration = json_decode($this->paymentMethods->getData($quoteId), true); + + if (!isset($paymentMethodsConfiguration['paymentMethodsExtraDetails'])) { + return []; + } + + return array_keys($paymentMethodsConfiguration['paymentMethodsExtraDetails']); + } + + /** + * @param array $list + * @return array + */ + private function handleApplePay(array $list): array + { + // TODO: Verify detection of Safari browser + $user_agent = $_SERVER['HTTP_USER_AGENT']; + + if (preg_match('/safari/i', $user_agent)) { + return $list; + } + + foreach ($list as $key => $method) { + if ($method->getCode() == ProcessingMetadataInterface::METHOD_APPLE_PAY) { + unset($list[$key]); + } + } + + return $list; + } +} diff --git a/ViewModel/SavedCards.php b/ViewModel/SavedCards.php new file mode 100644 index 00000000..aa1a7da0 --- /dev/null +++ b/ViewModel/SavedCards.php @@ -0,0 +1,22 @@ +savedCardsManager = $savedCardsManager; + } + + public function getStoredCards() + { + return $this->savedCardsManager->getStoredCards(); + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..ab7159cb --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "adyen/module-hyva-checkout", + "description": "Adyen Integration with Hyva Checkout", + "version": "100.0.0", + "type": "magento2-module", + "require": { + "adyen/module-payment": "9.0.5", + "hyva-themes/magento2-default-theme": "^1.3" + }, + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Adyen\\Hyva\\": "" + } + } +} diff --git a/etc/di.xml b/etc/di.xml new file mode 100644 index 00000000..2725a7e8 --- /dev/null +++ b/etc/di.xml @@ -0,0 +1,26 @@ + + + + + + + + + + adyen_cc + adyen_googlepay + adyen_applepay + adyen_paypal + + + + + + + + Adyen\Hyva\Model\CheckoutSession\ResetHandler\QuoteStatus + + + + diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml new file mode 100644 index 00000000..172fc775 --- /dev/null +++ b/etc/frontend/di.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/etc/frontend/events.xml b/etc/frontend/events.xml new file mode 100644 index 00000000..cd548a39 --- /dev/null +++ b/etc/frontend/events.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/view/frontend/layout/checkout_onepage_success.xml b/view/frontend/layout/checkout_onepage_success.xml new file mode 100644 index 00000000..fd86bc5c --- /dev/null +++ b/view/frontend/layout/checkout_onepage_success.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + Adyen\Hyva\Magewire\Checkout\Success + + + Adyen_Hyva::checkout/success.phtml + + + + diff --git a/view/frontend/layout/hyva_checkout_components.xml b/view/frontend/layout/hyva_checkout_components.xml new file mode 100644 index 00000000..2adec8ed --- /dev/null +++ b/view/frontend/layout/hyva_checkout_components.xml @@ -0,0 +1,54 @@ + + + + + + + + + \Adyen\Hyva\Magewire\Checkout\CouponCode + + + + + + + + + + + Adyen\Hyva\Magewire\Payment\Method\CreditCard + + + + + + Adyen\Hyva\Magewire\Payment\Method\GooglePay + + + + + + Adyen\Hyva\Magewire\Payment\Method\ApplePay + + + + + + Adyen\Hyva\Magewire\Payment\Method\Paypal + + + + + diff --git a/view/frontend/layout/hyva_checkout_index_index.xml b/view/frontend/layout/hyva_checkout_index_index.xml new file mode 100644 index 00000000..938bb4a1 --- /dev/null +++ b/view/frontend/layout/hyva_checkout_index_index.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/view/frontend/templates/checkout/payment/method-list.phtml b/view/frontend/templates/checkout/payment/method-list.phtml new file mode 100644 index 00000000..14733b1d --- /dev/null +++ b/view/frontend/templates/checkout/payment/method-list.phtml @@ -0,0 +1,90 @@ +require(ViewModel::class); +$methods = $viewModel->getList(); +?> +
+ + + +
    + getChildHtml('adyen_vault_saved_cards');?> + + escapeHtmlAttr($method->getCode()) ?> + getMethodMetaData($block, $method) ?> + +
  1. +
    +
    + +
    + + +
    + canShowMethod($block, $method, $magewire->method)): ?> + getMethodBlock($block, $method)->toHtml() ?> + + +
    + +
    + + +
  2. + +
+ +
+ escapeHtml(__('No Payment method available.')) ?> +
+ +
diff --git a/view/frontend/templates/checkout/payment/method-list/saved-cards.phtml b/view/frontend/templates/checkout/payment/method-list/saved-cards.phtml new file mode 100644 index 00000000..aef171f1 --- /dev/null +++ b/view/frontend/templates/checkout/payment/method-list/saved-cards.phtml @@ -0,0 +1,56 @@ +require(SavedCardsViewModel::class); +$paymentMethodsWire = $block->getHyvaPaymentMethodsMagewire(); + +?> + + + getStoredCards() as $storedCard): ?> +
  • + getNewVaultBlock($storedCard); + $vaultMethodHtml = $vaultMethod != null ? $vaultMethod->toHtml() : null; + ?> + +
    +
    + +
    + +
    + method == $storedCard->getLayoutId()) && $vaultMethodHtml): ?> +
    + +
    + +
  • + + diff --git a/view/frontend/templates/checkout/success.phtml b/view/frontend/templates/checkout/success.phtml new file mode 100644 index 00000000..1cf0d80c --- /dev/null +++ b/view/frontend/templates/checkout/success.phtml @@ -0,0 +1,83 @@ +
    + showAdyenGiving()): ?> +
    + + +
    diff --git a/view/frontend/templates/payment/init/init.phtml b/view/frontend/templates/payment/init/init.phtml new file mode 100644 index 00000000..95396f8f --- /dev/null +++ b/view/frontend/templates/payment/init/init.phtml @@ -0,0 +1,35 @@ + + + + +getChildHtml('checkout.payment.method.model.common'); ?> diff --git a/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml new file mode 100644 index 00000000..53a4e457 --- /dev/null +++ b/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml @@ -0,0 +1,83 @@ + + +
    +
    + + +
    diff --git a/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml new file mode 100644 index 00000000..a43b6cbb --- /dev/null +++ b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml @@ -0,0 +1,76 @@ + + +
    +
    + + +
    diff --git a/view/frontend/templates/payment/method-renderer/adyen-cc-vault-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-cc-vault-method.phtml new file mode 100644 index 00000000..64099486 --- /dev/null +++ b/view/frontend/templates/payment/method-renderer/adyen-cc-vault-method.phtml @@ -0,0 +1,84 @@ +getData(ProcessingMetadataInterface::BLOCK_PROPERTY_MAGEWIRE); +/** @var StoredCreditCardInterface $storedCard */ +$storedCard = $this->getData(ProcessingMetadataInterface::BLOCK_PROPERTY_STORED_CARD); +?> + +
    + +
    + + + +
    diff --git a/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml new file mode 100644 index 00000000..28bc22cf --- /dev/null +++ b/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml @@ -0,0 +1,82 @@ + + +
    +
    + + +
    diff --git a/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml new file mode 100644 index 00000000..8833a4db --- /dev/null +++ b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml @@ -0,0 +1,80 @@ + + +
    +
    + + +
    diff --git a/view/frontend/templates/payment/model/adyen-payment-method.phtml b/view/frontend/templates/payment/model/adyen-payment-method.phtml new file mode 100644 index 00000000..64b6f4c4 --- /dev/null +++ b/view/frontend/templates/payment/model/adyen-payment-method.phtml @@ -0,0 +1,263 @@ +require(Modal::class); + +$environment = $block->getConfiguration()->getValue('adyen/checkoutEnvironment'); +$shippingAddress = $block->getQuoteShippingAddress(); +$billingAddress = $block->getQuoteBillingAddress(); + +?> +
    + createModal() + ->withDialogRefName('adyenPopup') + ->removeDialogClass('p-10') + ->addDialogClass('p-4') + ->withContent(<< + {$block->getBlockHtml('block-loader')} +
    +
    + END_OF_CONTENT + ) ?> + + + + + + +getChildNames() as $childBlockName) { + echo $block->getLayout()->getBlock($childBlockName)->toHtml(); + } +?> From ae2f998930c0282d094c2f71b1c0ec7d5930639b Mon Sep 17 00:00:00 2001 From: Marjan Date: Mon, 5 Feb 2024 17:23:50 +0100 Subject: [PATCH 02/40] Add registration.php --- registration.php | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 registration.php diff --git a/registration.php b/registration.php new file mode 100644 index 00000000..d305f668 --- /dev/null +++ b/registration.php @@ -0,0 +1,5 @@ + Date: Mon, 5 Feb 2024 17:31:56 +0100 Subject: [PATCH 03/40] Add module.xml --- etc/module.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 etc/module.xml diff --git a/etc/module.xml b/etc/module.xml new file mode 100644 index 00000000..813b91c0 --- /dev/null +++ b/etc/module.xml @@ -0,0 +1,10 @@ + + + + + + + + + + From 1cb0edf34f8fe5b5a9b7e6df3a3c53253881d9d9 Mon Sep 17 00:00:00 2001 From: Marjan Date: Tue, 6 Feb 2024 12:51:09 +0100 Subject: [PATCH 04/40] Add missing files --- Block/HyvaCheckout.php | 29 +++++++++++++ Model/PaymentMethod/PaymentMethods.php | 31 ++++++++++++++ Observer/PaymentTokenAssigner.php | 58 ++++++++++++++++++++++++++ README.md | 32 +++++++++++++- 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 Block/HyvaCheckout.php create mode 100644 Model/PaymentMethod/PaymentMethods.php create mode 100644 Observer/PaymentTokenAssigner.php diff --git a/Block/HyvaCheckout.php b/Block/HyvaCheckout.php new file mode 100644 index 00000000..6214da92 --- /dev/null +++ b/Block/HyvaCheckout.php @@ -0,0 +1,29 @@ +methodList = $methodList; + } + + /** + * @return array + */ + public function getSupportedMethods(): array + { + return array_values($this->methodList->collectAvailableMethods()); + } +} diff --git a/Model/PaymentMethod/PaymentMethods.php b/Model/PaymentMethod/PaymentMethods.php new file mode 100644 index 00000000..eb207efe --- /dev/null +++ b/Model/PaymentMethod/PaymentMethods.php @@ -0,0 +1,31 @@ +adyenPaymentMethods = $adyenPaymentMethods; + } + + /** + * @param int $quoteId + * @return string + */ + public function getData(int $quoteId): string + { + $paymentMethods = json_decode($this->adyenPaymentMethods->getPaymentMethods($quoteId), true); + + if (isset($paymentMethods['paymentMethodsResponse']['storedPaymentMethods'])) { + unset($paymentMethods['paymentMethodsResponse']['storedPaymentMethods']); + } + + return json_encode($paymentMethods); + } +} diff --git a/Observer/PaymentTokenAssigner.php b/Observer/PaymentTokenAssigner.php new file mode 100644 index 00000000..908dfcb5 --- /dev/null +++ b/Observer/PaymentTokenAssigner.php @@ -0,0 +1,58 @@ +checkoutSession = $checkoutSession; + $this->paymentTokenManagement = $paymentTokenManagement; + } + + /** + * @inheritDoc + */ + public function execute(Observer $observer) + { + /** @var Payment $paymentModel */ + $paymentModel = $this->readPaymentModelArgument($observer); + + if (!$paymentModel instanceof Payment) { + return; + } + + $quote = $paymentModel->getQuote(); + $tokenPublicHash = $this->checkoutSession->getSavedCardPublicHash(); + + if (!$tokenPublicHash) { + return; + } + + $customerId = (int) $quote->getCustomer()->getId(); + $paymentToken = $this->paymentTokenManagement->getByPublicHash($tokenPublicHash, $customerId); + + if ($paymentToken === null) { + return; + } + + $paymentModel->setAdditionalInformation( + [ + PaymentTokenInterface::CUSTOMER_ID => $customerId, + PaymentTokenInterface::PUBLIC_HASH => $tokenPublicHash + ] + ); + } +} diff --git a/README.md b/README.md index 8b878aea..61521fbd 100644 --- a/README.md +++ b/README.md @@ -1 +1,31 @@ -# adyen-magento2-hyva \ No newline at end of file +#Adyen Payment - Integration with Hyva Checkout + +This module supports Adyen payments via the Hyva Checkout implementation for Magento 2. + +### Supported methods + +The following payment methods are supported: + + - Credit card + - Saved (Tokenized) credit card + - Google pay + +### Magewire usage + +Each payment method implementation depends on the work of a magewire component. (https://github.com/magewirephp/magewire) + +Reference classes are located under the `Adyen\Hyva\Magewire\Payment\Method` namespace. + +#### PSI compliance +When making an order, the state data is extracted from the request parameters, +and the state data is temporarily attached (but never persisted) to the Adyen's native State Data Object (`Adyen\Payment\Helper\StateData`). + +#### Development Assumptions + +This module is developed under a couple of assumptions: +- this module does not add its own configuration +- this module only reuses configuration that is coming from Adyen, it does not extend or alter in any way native Adyen configuration +- it assumes dependency on the `Adyen_payment` module, with the following ideas + - interfaces from the `Adyen_Payment` may be injected into classes of `Adyen_Hyva` + - it must be avoided (to the extent that it is possible), to plugin to any, or take preference of any, native classes from the native `Adyen_Payment` module + From 6f7b1a8e1881f165fb9008bd02be9addb4dbd1f8 Mon Sep 17 00:00:00 2001 From: Marjan Date: Tue, 6 Feb 2024 15:13:02 +0100 Subject: [PATCH 05/40] Modifications for pull no.2 review, dated 05.02.2024 --- Block/PaymentMethod.php | 28 +++++++++++++++++-- Magewire/Checkout/CouponCode.php | 2 +- .../checkout/payment/method-list.phtml | 16 +++++------ .../payment/method-list/saved-cards.phtml | 12 ++++---- .../method-renderer/adyen-cc-method.phtml | 6 ++-- .../adyen-cc-vault-method.phtml | 6 ++-- .../adyen-googlepay-method.phtml | 22 +++++++-------- 7 files changed, 58 insertions(+), 34 deletions(-) diff --git a/Block/PaymentMethod.php b/Block/PaymentMethod.php index d0ea666d..529e8064 100644 --- a/Block/PaymentMethod.php +++ b/Block/PaymentMethod.php @@ -5,6 +5,7 @@ use Magento\Checkout\Model\Session; use Magento\Framework\View\Element\Template; use Adyen\Hyva\Model\Configuration; +use Magento\Quote\Model\Quote; class PaymentMethod extends Template { @@ -33,11 +34,34 @@ public function getConfiguration(): Configuration public function getQuoteShippingAddress() { - return json_encode($this->checkoutSession->getQuote()->getShippingAddress()->getData()); + $quote = $this->getQuote(); + + if ($quote->getShippingAddress()) { + return json_encode($quote->getShippingAddress()->getData()); + } + + return json_encode([]); } public function getQuoteBillingAddress() { - return json_encode($this->checkoutSession->getQuote()->getBillingAddress()->getData()); + $quote = $this->getQuote(); + + if ($quote->getBillingAddress()) { + return json_encode($quote->getBillingAddress()->getData()); + } + + return json_encode([]); + } + + /** + * @return Quote + */ + private function getQuote(): Quote + { + /** @var Quote $quote */ + $quote = $this->checkoutSession->getQuote(); + + return $quote; } } diff --git a/Magewire/Checkout/CouponCode.php b/Magewire/Checkout/CouponCode.php index b4ab866b..c54e5ded 100644 --- a/Magewire/Checkout/CouponCode.php +++ b/Magewire/Checkout/CouponCode.php @@ -43,7 +43,7 @@ public function applyCouponCode() __('No Coupon') ); } - if (! empty($this->couponManagement->get($quoteEntity))) { + if (!empty($this->couponManagement->get($quoteEntity))) { throw new LocalizedException( __('A coupon is already applied to the cart. Please remove it to apply another') ); diff --git a/view/frontend/templates/checkout/payment/method-list.phtml b/view/frontend/templates/checkout/payment/method-list.phtml index 14733b1d..d7432459 100644 --- a/view/frontend/templates/checkout/payment/method-list.phtml +++ b/view/frontend/templates/checkout/payment/method-list.phtml @@ -32,26 +32,26 @@ $methods = $viewModel->getList();
      getChildHtml('adyen_vault_saved_cards');?> - escapeHtmlAttr($method->getCode()) ?> + getCode() ?> getMethodMetaData($block, $method) ?> -
    1. getHyvaPaymentMethodsMagewire();
    2. From 077d122702c7fb39914c6f8a9e82d76a088c2579 Mon Sep 17 00:00:00 2001 From: Marjan Date: Thu, 21 Mar 2024 17:44:03 +0100 Subject: [PATCH 24/40] #31: Refresh card brands when reloading the component --- Magewire/Payment/Method/CreditCard.php | 10 +++++----- .../payment/method-renderer/adyen-cc-method.phtml | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Magewire/Payment/Method/CreditCard.php b/Magewire/Payment/Method/CreditCard.php index c069d86d..11a6da0d 100644 --- a/Magewire/Payment/Method/CreditCard.php +++ b/Magewire/Payment/Method/CreditCard.php @@ -14,6 +14,8 @@ class CreditCard extends AdyenPaymentComponent { const METHOD_CC = 'adyen_cc'; + public ?string $cardBrands = null; + public function __construct( private readonly Context $context, private readonly BrandsManager $brandsManager, @@ -39,12 +41,10 @@ public function evaluateCompletion(EvaluationResultFactory $resultFactory): Eval return $resultFactory->createSuccess(); } - /** - * @return string - */ - public function getBrands(): string + public function refreshProperties(): void { - return $this->brandsManager->getBrands(); + $this->cardBrands = $this->brandsManager->getBrands(); + parent::refreshProperties(); } /** diff --git a/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml index 9ccc50f2..7dc5372f 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml @@ -41,10 +41,9 @@ use Adyen\Hyva\Magewire\Payment\Method\CreditCard; } else { let rawResponse = wire.get('paymentResponse'); let paymentMethods = JSON.parse(rawResponse); - let configuration = { enableStoreDetails: 'escapeJs($magewire->getConfiguration()->isCCEnableStoreDetails($magewire->userIsGuest()))?>', - brands: getBrands() ?>, + brands: JSON.parse(wire.get('cardBrands')), hasHolderName: 'escapeJs($magewire->getConfiguration()->getValue('adyen/hasHolderName')) ?>', holderNameRequired: 'escapeJs($magewire->getConfiguration()->getValue('adyen/holderNameRequired')) ?>', installmentOptions: getFormattedInstallments() ?>, From 5f139f8c563af2720f07b4655c085f7038fc7e85 Mon Sep 17 00:00:00 2001 From: Marjan Date: Sun, 24 Mar 2024 10:47:40 +0100 Subject: [PATCH 25/40] #31: Refresh card brands when switching addresses for customer --- Magewire/Payment/Method/AdyenPaymentComponent.php | 4 ++++ Magewire/Payment/Method/CreditCard.php | 1 - .../payment/method-renderer/adyen-applepay-method.phtml | 1 + .../templates/payment/method-renderer/adyen-cc-method.phtml | 1 + .../payment/method-renderer/adyen-cc-vault-method.phtml | 1 + .../payment/method-renderer/adyen-googlepay-method.phtml | 1 + .../payment/method-renderer/adyen-paypal-method.phtml | 1 + .../templates/payment/model/adyen-payment-method.phtml | 4 ++++ 8 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Magewire/Payment/Method/AdyenPaymentComponent.php b/Magewire/Payment/Method/AdyenPaymentComponent.php index 4d30cf01..8d176221 100644 --- a/Magewire/Payment/Method/AdyenPaymentComponent.php +++ b/Magewire/Payment/Method/AdyenPaymentComponent.php @@ -61,6 +61,10 @@ public function __construct( 'coupon_code_revoked' => 'refreshProperties', 'shipping_address_saved' => 'refreshProperties', 'billing_address_saved' => 'refreshProperties', + 'shipping_address_submitted' => 'refreshProperties', + 'billing_address_submitted' => 'refreshProperties', + 'shipping_address_activated' => 'refreshProperties', + 'billing_address_activated' => 'refreshProperties', ]; /** diff --git a/Magewire/Payment/Method/CreditCard.php b/Magewire/Payment/Method/CreditCard.php index 11a6da0d..b6320523 100644 --- a/Magewire/Payment/Method/CreditCard.php +++ b/Magewire/Payment/Method/CreditCard.php @@ -13,7 +13,6 @@ class CreditCard extends AdyenPaymentComponent { const METHOD_CC = 'adyen_cc'; - public ?string $cardBrands = null; public function __construct( diff --git a/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml index dc83b1ae..c5214fbc 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml @@ -37,6 +37,7 @@ use Adyen\Hyva\Magewire\Payment\Method\ApplePay; async function init(methodCode) { try { + clearContainer('ApplePayActionContainer'); let wire = Magewire.find('checkout.payment.method.' + methodCode); let applePayHandler = new applePayComponentHandler( methodCode, diff --git a/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml index 7dc5372f..a87cc1cd 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml @@ -24,6 +24,7 @@ use Adyen\Hyva\Magewire\Payment\Method\CreditCard; async function init(methodCode) { try { + clearContainer('CreditCardActionContainer'); let wire = Magewire.find('checkout.payment.method.' + methodCode); let creditCardHandler = new componentHandler( methodCode, diff --git a/view/frontend/templates/payment/method-renderer/adyen-cc-vault-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-cc-vault-method.phtml index 3d31bf24..ca1c17c1 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-cc-vault-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-cc-vault-method.phtml @@ -29,6 +29,7 @@ $storedCard = $this->getData(ProcessingMetadataInterface::BLOCK_PROPERTY_STORED_ async function init(cardLayoutId) { try { + clearContainer(cardLayoutId + '_ActionContainer'); let magewireMethodCode = 'escapeJs($magewire->getMethodCode()) ?>'; let wire = Magewire.find(cardLayoutId); diff --git a/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml index 09415ee0..0b3bfeeb 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml @@ -35,6 +35,7 @@ use Adyen\Hyva\Magewire\Payment\Method\GooglePay; async function init(methodCode) { try { + clearContainer('GooglePayActionContainer'); let wire = Magewire.find('checkout.payment.method.' + methodCode); let googlePayHandler = new googlePayComponentHandler( methodCode, diff --git a/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml index 0a76f1e2..0ad89916 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml @@ -34,6 +34,7 @@ use Adyen\Hyva\Magewire\Payment\Method\Paypal; async function init(methodCode) { try { + clearContainer('PaypalActionContainer'); let wire = Magewire.find('checkout.payment.method.' + methodCode); let paypalHandler = new paypalComponentHandler( methodCode, diff --git a/view/frontend/templates/payment/model/adyen-payment-method.phtml b/view/frontend/templates/payment/model/adyen-payment-method.phtml index ee012ea6..b2a1f6b5 100644 --- a/view/frontend/templates/payment/model/adyen-payment-method.phtml +++ b/view/frontend/templates/payment/model/adyen-payment-method.phtml @@ -32,6 +32,10 @@ $billingAddress = $block->getQuoteBillingAddress(); From 21c871053c3775ffd56026a8f6d7cd659b9e27e9 Mon Sep 17 00:00:00 2001 From: Marjan Date: Wed, 3 Apr 2024 20:43:40 +0200 Subject: [PATCH 33/40] #33: Use explicit component unmount #28: Switch address for customer #29: Switch address for guest --- .../Payment/Method/AdyenPaymentComponent.php | 18 ---- Magewire/Payment/MethodList.php | 85 +++++++++++++++++ .../layout/hyva_checkout_components.xml | 4 + .../adyen-applepay-method.phtml | 47 ++++++---- .../method-renderer/adyen-cc-method.phtml | 93 ++++++++++--------- .../adyen-cc-vault-method.phtml | 92 +++++++++--------- .../adyen-googlepay-method.phtml | 50 +++++----- .../method-renderer/adyen-paypal-method.phtml | 51 +++++----- .../payment/model/adyen-payment-method.phtml | 8 +- 9 files changed, 277 insertions(+), 171 deletions(-) create mode 100644 Magewire/Payment/MethodList.php diff --git a/Magewire/Payment/Method/AdyenPaymentComponent.php b/Magewire/Payment/Method/AdyenPaymentComponent.php index b06428f5..dd5f9560 100644 --- a/Magewire/Payment/Method/AdyenPaymentComponent.php +++ b/Magewire/Payment/Method/AdyenPaymentComponent.php @@ -56,9 +56,6 @@ public function __construct( } protected $listeners = [ - 'shipping_method_selected' => 'refreshProperties', - 'coupon_code_applied' => 'refreshProperties', - 'coupon_code_revoked' => 'refreshProperties', ]; /** @@ -125,7 +122,6 @@ public function refreshProperties(): void { $this->processRequiresShipping(); $this->processPaymentResponse(); - $this->dispatchCustomEvent(); } /** @@ -215,18 +211,4 @@ private function processPaymentResponse(): void $this->logger->error('Could not collect Adyen payment methods response: ' . $e->getMessage()); } } - - /** - * Dispatches a custom event that frontend parts of payment methods depend on to refresh the component - */ - private function dispatchCustomEvent(): void - { - try { - $this->dispatchBrowserEvent('adyen:payment_component:refresh', - ['method' => $this->session->getQuote()->getPayment()->getMethod()] - ); - } catch (\Exception $e) { - $this->logger->error('Could not dispatch the browser event adyen:payment_component:refresh: ' . $e->getMessage()); - } - } } diff --git a/Magewire/Payment/MethodList.php b/Magewire/Payment/MethodList.php new file mode 100644 index 00000000..e9b4da8c --- /dev/null +++ b/Magewire/Payment/MethodList.php @@ -0,0 +1,85 @@ + 'refresh', + 'shipping_address_saved' => 'refresh', + 'coupon_code_applied' => 'refresh', + 'coupon_code_revoked' => 'refresh', + //Refreshing the method list after the shipping method has been selected + 'shipping_method_selected' => 'refresh', + //Refreshing the method list after the shipping address has been activated + 'shipping_address_activated' => 'refresh', + ]; + + protected $loader = [ + 'method' => 'Saving method' + ]; + + public function __construct( + protected readonly SessionCheckout $sessionCheckout, + protected readonly CartRepositoryInterface $cartRepository, + protected readonly EvaluationResultFactory $evaluationResultFactory + ) { + } + + public function boot(): void + { + try { + $method = $this->sessionCheckout->getQuote()->getPayment()->getMethod(); + } catch (LocalizedException $exception) { + $method = null; + } + + $this->method = $method; + //This custom event notifies that the method list has rebooted + $this->dispatchBrowserEvent('checkout:payment:method-list-boot', ['method' => $method]); + } + + public function updatedMethod(string $value): string + { + try { + $quote = $this->sessionCheckout->getQuote(); + $quote->getPayment()->setMethod($value); + + $this->cartRepository->save($quote); + + $this->dispatchBrowserEvent('checkout:payment:method-activate', ['method' => $value]); + $this->emit('payment_method_selected'); + } catch (LocalizedException $exception) { + $this->dispatchErrorMessage('Something went wrong while saving your payment preferences.'); + } + + return $value; + } + + public function evaluateCompletion(EvaluationResultFactory $resultFactory): EvaluationResultInterface + { + if ($this->method === null) { + return $resultFactory->createErrorMessageEvent() + ->withCustomEvent('payment:method:error') + ->withMessage('The payment method is missing. Select the payment method and try again.'); + } + + return $resultFactory->createSuccess([], 'payment:method:success'); + } +} + diff --git a/view/frontend/layout/hyva_checkout_components.xml b/view/frontend/layout/hyva_checkout_components.xml index 613bce26..6d0e292e 100644 --- a/view/frontend/layout/hyva_checkout_components.xml +++ b/view/frontend/layout/hyva_checkout_components.xml @@ -4,6 +4,10 @@ + + Adyen\Hyva\Magewire\Payment\MethodList + + { + window.addEventListener('checkout:payment:method-list-boot', async (event) => { + unmountAdyenComponent(); await init(event.detail.method); }); - window.addEventListener('adyen:payment_component:refresh', async (event) => { + window.addEventListener('checkout:payment:method-activate', async (event) => { await init(event.detail.method); }); async function init(methodCode) { try { - clearContainer('ApplePayActionContainer'); let wire = Magewire.find('checkout.payment.method.' + methodCode); - let applePayHandler = new applePayComponentHandler( - methodCode, - wire, - 'ApplePayActionContainer' - ); + wire.refreshProperties() + .then(() => { + let applePayHandler = new applePayComponentHandler( + methodCode, + wire, + 'ApplePayActionContainer' + ); + + window.AdyenPaymentHandler = applePayHandler; - if (methodCode !== 'adyen_applepay') { - applePayHandler.renderMethodUnavailableMessage(); - return; - } + if (methodCode !== 'adyen_applepay') { + applePayHandler.renderMethodUnavailableMessage(); + return; + } - if (wire.get('requiresShipping')) { - applePayHandler.renderMessage('Please select shipping method.'); - } else { - let rawResponse = wire.get('paymentResponse'); - let paymentMethods = JSON.parse(rawResponse); - await applePayHandler.activateWalletMethod(methodCode, paymentMethods); - hidePrimaryButton(); - } + if (wire.get('requiresShipping')) { + applePayHandler.renderMessage('Please select shipping method.'); + } else { + let rawResponse = wire.get('paymentResponse'); + let paymentMethods = JSON.parse(rawResponse); + applePayHandler.activateWalletMethod(methodCode, paymentMethods); + hidePrimaryButton(); + } + }).catch(() => { + console.log('Error occurred during Applepay component load') + }); } catch (e) { } } diff --git a/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml index a7cd33c2..5d11f163 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml @@ -14,61 +14,68 @@ use Adyen\Hyva\Magewire\Payment\Method\CreditCard;
      diff --git a/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml index 0b3bfeeb..d7b82597 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml @@ -25,37 +25,43 @@ use Adyen\Hyva\Magewire\Payment\Method\GooglePay; } } - window.addEventListener('checkout:payment:method-activate', async (event) => { + window.addEventListener('checkout:payment:method-list-boot', async (event) => { + unmountAdyenComponent(); await init(event.detail.method); }); - window.addEventListener('adyen:payment_component:refresh', async (event) => { + window.addEventListener('checkout:payment:method-activate', async (event) => { await init(event.detail.method); }); async function init(methodCode) { try { - clearContainer('GooglePayActionContainer'); let wire = Magewire.find('checkout.payment.method.' + methodCode); - let googlePayHandler = new googlePayComponentHandler( - methodCode, - wire, - 'GooglePayActionContainer' - ); - - if (methodCode !== 'adyen_googlepay') { - googlePayHandler.renderMethodUnavailableMessage(); - return; - } - - if (wire.get('requiresShipping')) { - googlePayHandler.renderMessage('Please select shipping method.'); - } else { - let rawResponse = wire.get('paymentResponse'); - let paymentMethods = JSON.parse(rawResponse); - await googlePayHandler.activateWalletMethod(methodCode, paymentMethods); - hidePrimaryButton(); - } + wire.refreshProperties() + .then(() => { + let googlePayHandler = new googlePayComponentHandler( + methodCode, + wire, + 'GooglePayActionContainer' + ); + + window.AdyenPaymentHandler = googlePayHandler; + + if (methodCode !== 'adyen_googlepay') { + googlePayHandler.renderMethodUnavailableMessage(); + return; + } + + if (wire.get('requiresShipping')) { + googlePayHandler.renderMessage('Please select shipping method.'); + } else { + let rawResponse = wire.get('paymentResponse'); + let paymentMethods = JSON.parse(rawResponse); + googlePayHandler.activateWalletMethod(methodCode, paymentMethods); + hidePrimaryButton(); + } + }) + .catch(() => {}); } catch (e) { } } diff --git a/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml index 0ad89916..20716c03 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml @@ -24,37 +24,44 @@ use Adyen\Hyva\Magewire\Payment\Method\Paypal; } } - window.addEventListener('checkout:payment:method-activate', async (event) => { + window.addEventListener('checkout:payment:method-list-boot', async (event) => { + unmountAdyenComponent(); await init(event.detail.method); }); - window.addEventListener('adyen:payment_component:refresh', async (event) => { + window.addEventListener('checkout:payment:method-activate', async (event) => { await init(event.detail.method); }); async function init(methodCode) { try { - clearContainer('PaypalActionContainer'); let wire = Magewire.find('checkout.payment.method.' + methodCode); - let paypalHandler = new paypalComponentHandler( - methodCode, - wire, - 'PaypalActionContainer' - ); - - if (methodCode !== 'adyen_paypal') { - paypalHandler.renderMethodUnavailableMessage(); - return; - } - - if (wire.get('requiresShipping')) { - paypalHandler.renderMessage('Please select shipping method.'); - } else { - let rawResponse = wire.get('paymentResponse'); - let paymentMethods = JSON.parse(rawResponse); - await paypalHandler.activateWalletMethod(methodCode, paymentMethods); - hidePrimaryButton(); - } + wire.refreshProperties() + .then(() => { + let paypalHandler = new paypalComponentHandler( + methodCode, + wire, + 'PaypalActionContainer' + ); + + window.AdyenPaymentHandler = paypalHandler; + + if (methodCode !== 'adyen_paypal') { + paypalHandler.renderMethodUnavailableMessage(); + return; + } + + if (wire.get('requiresShipping')) { + paypalHandler.renderMessage('Please select shipping method.'); + } else { + let rawResponse = wire.get('paymentResponse'); + let paymentMethods = JSON.parse(rawResponse); + paypalHandler.activateWalletMethod(methodCode, paymentMethods); + hidePrimaryButton(); + } + }).catch(() => { + console.log('Error occurred during Paypal component load') + }); } catch (e) { } } diff --git a/view/frontend/templates/payment/model/adyen-payment-method.phtml b/view/frontend/templates/payment/model/adyen-payment-method.phtml index e077a3b0..d300517a 100644 --- a/view/frontend/templates/payment/model/adyen-payment-method.phtml +++ b/view/frontend/templates/payment/model/adyen-payment-method.phtml @@ -32,9 +32,11 @@ $billingAddress = $block->getQuoteBillingAddress(); + diff --git a/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml index 20716c03..5f9533fe 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml @@ -56,7 +56,7 @@ use Adyen\Hyva\Magewire\Payment\Method\Paypal; } else { let rawResponse = wire.get('paymentResponse'); let paymentMethods = JSON.parse(rawResponse); - paypalHandler.activateWalletMethod(methodCode, paymentMethods); + paypalHandler.activatePaymentMethod(methodCode, paymentMethods); hidePrimaryButton(); } }).catch(() => { diff --git a/view/frontend/templates/payment/model/adyen-payment-method.phtml b/view/frontend/templates/payment/model/adyen-payment-method.phtml index d300517a..601dc687 100644 --- a/view/frontend/templates/payment/model/adyen-payment-method.phtml +++ b/view/frontend/templates/payment/model/adyen-payment-method.phtml @@ -192,37 +192,62 @@ $billingAddress = $block->getQuoteBillingAddress(); ); } - async activateWalletMethod(methodCode, paymentMethods) { + async activatePaymentMethod(methodCode, paymentMethods, element = null) { let self = this; + let component; - let walletMethodConfiguration = self.collectWalletMethodConfiguration( + let paymentMethodConfiguration = self.collectPaymentMethodConfiguration( paymentMethods, methodCode.split("_").pop() ); - if (walletMethodConfiguration !== null) { + if (paymentMethodConfiguration !== null) { let configuration = self.buildConfiguration( - walletMethodConfiguration, + paymentMethodConfiguration, paymentMethods.paymentMethodsExtraDetails ); - let component = await self.buildComponent( - paymentMethods.paymentMethodsResponse, - function (result) { - self.handleAdditionalDetails(result.data) - }, - function (result) {}, - function (state) { - self.placeOrder(state.data); - } - ); - self.mountComponent(component, walletMethodConfiguration.type, configuration); + if (configuration.showPayButton) { + component = await self.buildComponent( + paymentMethods.paymentMethodsResponse, + function (result) { + self.handleAdditionalDetails(result.data) + }, + function (result) {}, + function (state) { + self.placeOrder(state.data); + } + ); + + self.mountComponent(component, paymentMethodConfiguration.type, configuration); + } else if (element !== null) { + component = await self.buildComponent( + paymentMethods.paymentMethodsResponse + ); + + self.mountComponent(component, paymentMethodConfiguration.type, configuration); + + hyvaCheckout.payment.activate(methodCode, + { + async placeOrder() { + let stateData = self.getActionComponent().data; + self.placeOrder(stateData); + }, + placeOrderViaJs() { + return true + } + }, + document.getElementById(element) + ); + + hyvaCheckout.navigation.enableButtonPlaceOrder(); + } } else { self.renderMethodUnavailableMessage(); } } - collectWalletMethodConfiguration(paymentMethods, walletCode) { + collectPaymentMethodConfiguration(paymentMethods, methodCode) { let methodConfiguration = null; if (paymentMethods.hasOwnProperty('paymentMethodsResponse') @@ -231,7 +256,7 @@ $billingAddress = $block->getQuoteBillingAddress(); let methods = paymentMethods.paymentMethodsResponse.paymentMethods; for (let i = 0; i < methods.length; i++) { - if (methods[i].type == walletCode) { + if (methods[i].type == methodCode) { methodConfiguration = methods[i]; break; } @@ -360,9 +385,7 @@ $billingAddress = $block->getQuoteBillingAddress(); self.getCheckoutComponent().createFromAction(action).mount('#adyen-popup'); this.handleModal(true) - } - - if (action.type === 'sdk') { + } else { let component = self.getCheckoutComponent().components.at(0); if (component) { From 84e80a9da42cd1d8c28b75f6349fba8c1de9f694 Mon Sep 17 00:00:00 2001 From: khushboos Date: Wed, 15 May 2024 10:14:04 +0200 Subject: [PATCH 36/40] [ECP-9167] Bump the version of module-payment --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d3a59d38..e880631d 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "version": "100.0.0", "type": "magento2-module", "require": { - "adyen/module-payment": "9.2.0", + "adyen/module-payment": "^9.5.0", "hyva-themes/magento2-default-theme": "^1.3" }, "autoload": { From d94c3346c4fc50ae324c61b6878a1a0ba31001c9 Mon Sep 17 00:00:00 2001 From: Khushboo Date: Tue, 21 May 2024 09:26:05 +0200 Subject: [PATCH 37/40] [ECP-9161] Provide frontendType tracking data on Hyva module (#38) * [ECP-9161] Provide frontendType tracking data on Hyva module * Update Magewire/Payment/Method/AdyenPaymentComponent.php --------- Co-authored-by: Can Demiralp --- Magewire/Payment/Method/AdyenPaymentComponent.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Magewire/Payment/Method/AdyenPaymentComponent.php b/Magewire/Payment/Method/AdyenPaymentComponent.php index dd5f9560..881347bd 100644 --- a/Magewire/Payment/Method/AdyenPaymentComponent.php +++ b/Magewire/Payment/Method/AdyenPaymentComponent.php @@ -11,6 +11,7 @@ use Adyen\Hyva\Model\PaymentMethod\PaymentMethods; use Adyen\Payment\Api\AdyenOrderPaymentStatusInterface; use Adyen\Payment\Api\AdyenPaymentsDetailsInterface; +use Adyen\Payment\Gateway\Request\HeaderDataBuilder; use Adyen\Payment\Helper\StateData; use Adyen\Payment\Helper\Util\CheckoutStateDataValidator; use Hyva\Checkout\Model\Magewire\Component\Evaluation\EvaluationResult; @@ -40,6 +41,8 @@ abstract class AdyenPaymentComponent extends Component implements EvaluationInte protected CustomerGroupHandler $customerGroupHandler; protected LoggerInterface $logger; + const FRONTENDTYPE_HYVA = 'hyva'; + public function __construct( private readonly Context $context ) { @@ -80,6 +83,7 @@ public function placeOrder(array $data): void $this->handleSessionVariables($data); $quoteId = $this->session->getQuoteId(); $payment = $this->session->getQuote()->getPayment(); + $payment->setAdditionalInformation(HeaderDataBuilder::FRONTENDTYPE, self::FRONTENDTYPE_HYVA); $stateDataReceived = $this->collectValidatedStateData($data); //Temporary (per request) storage of state data $this->stateData->setStateData($stateDataReceived, (int) $quoteId); From 6df28e09031ec7a612e84336f30c0e8b3d194925 Mon Sep 17 00:00:00 2001 From: Marjan Petkovski <72909665+pmarjan-onestic@users.noreply.github.com> Date: Tue, 21 May 2024 16:41:48 +0200 Subject: [PATCH 38/40] #36: Unit tests (#39) * #36: Unit tests * #36: Unit tests: Reduce ApplePayTest.php code duplication * #36: Unit tests: Reduce BrandsManagerTest.php code duplication * #36: Unit tests: Reduce PaymentMethodsTest.php code duplication * #36: Unit tests: Reduce StoredCardsTest.php code duplication * #36: Unit tests: Reduce CreditCardTest.php code duplication * #36: Unit tests: Reduce code duplication * #36: Unit tests: Reduce code duplication * #36: Unit tests: Remove non needed vars --------- Co-authored-by: Khushboo --- Block/PaymentMethod.php | 2 +- Model/ThemeConfiguration.php | 45 --- Test/Unit/Block/PaymentMethodTest.php | 112 ++++++ Test/Unit/Magewire/Checkout/SuccessTest.php | 114 +++++++ .../Payment/Method/CreditCardTest.php | 318 ++++++++++++++++++ Test/Unit/Model/ConfigurationTest.php | 87 +++++ .../Model/CreditCard/BrandsManagerTest.php | 112 ++++++ .../CreditCard/InstallmentsManagerTest.php | 83 +++++ .../Customer/CustomerGroupHandlerTest.php | 65 ++++ Test/Unit/Model/MethodListTest.php | 31 ++ .../PaymentMethod/Filter/AdyenBasedTest.php | 67 ++++ .../Filter/AdyenConfiguredTest.php | 79 +++++ .../PaymentMethod/Filter/ApplePayTest.php | 113 +++++++ .../PaymentMethod/Filter/StoredCardsTest.php | 91 +++++ .../PaymentMethod/PaymentMethodsTest.php | 120 +++++++ .../Observer/InstallmentsDataAssignerTest.php | 72 ++++ .../Observer/PaymentTokenAssignerTest.php | 97 ++++++ Test/Unit/Plugin/InitMethodsTest.php | 75 +++++ 18 files changed, 1637 insertions(+), 46 deletions(-) delete mode 100644 Model/ThemeConfiguration.php create mode 100644 Test/Unit/Block/PaymentMethodTest.php create mode 100644 Test/Unit/Magewire/Checkout/SuccessTest.php create mode 100644 Test/Unit/Magewire/Payment/Method/CreditCardTest.php create mode 100644 Test/Unit/Model/ConfigurationTest.php create mode 100644 Test/Unit/Model/CreditCard/BrandsManagerTest.php create mode 100644 Test/Unit/Model/CreditCard/InstallmentsManagerTest.php create mode 100644 Test/Unit/Model/Customer/CustomerGroupHandlerTest.php create mode 100644 Test/Unit/Model/MethodListTest.php create mode 100644 Test/Unit/Model/PaymentMethod/Filter/AdyenBasedTest.php create mode 100644 Test/Unit/Model/PaymentMethod/Filter/AdyenConfiguredTest.php create mode 100644 Test/Unit/Model/PaymentMethod/Filter/ApplePayTest.php create mode 100644 Test/Unit/Model/PaymentMethod/Filter/StoredCardsTest.php create mode 100644 Test/Unit/Model/PaymentMethod/PaymentMethodsTest.php create mode 100644 Test/Unit/Observer/InstallmentsDataAssignerTest.php create mode 100644 Test/Unit/Observer/PaymentTokenAssignerTest.php create mode 100644 Test/Unit/Plugin/InitMethodsTest.php diff --git a/Block/PaymentMethod.php b/Block/PaymentMethod.php index 8c06fd81..4901ccea 100644 --- a/Block/PaymentMethod.php +++ b/Block/PaymentMethod.php @@ -44,7 +44,7 @@ public function getQuoteShippingAddress(): string $quote = $this->getQuote(); if ($quote && $quote->getShippingAddress()) { - return json_encode($quote->getShippingAddress()->getData()); + return $this->jsonSerializer->serialize($quote->getShippingAddress()->getData()); } } catch (\InvalidArgumentException $exception) { return $this->defaultResponse(); diff --git a/Model/ThemeConfiguration.php b/Model/ThemeConfiguration.php deleted file mode 100644 index 0747ed27..00000000 --- a/Model/ThemeConfiguration.php +++ /dev/null @@ -1,45 +0,0 @@ -getThemeCode(), 'Hyva')) { - return true; - } - - return false; - } - - /** - * @return string - */ - public function getThemeCode(): string - { - $themeId = $this->scopeConfig->getValue( - DesignInterface::XML_PATH_THEME_ID, - ScopeInterface::SCOPE_STORE, - $this->storeManager->getStore()->getId() - ); - - /** @var $theme ThemeInterface */ - $theme = $this->themeProvider->getThemeById($themeId); - - return $theme->getCode(); - } -} diff --git a/Test/Unit/Block/PaymentMethodTest.php b/Test/Unit/Block/PaymentMethodTest.php new file mode 100644 index 00000000..a2252561 --- /dev/null +++ b/Test/Unit/Block/PaymentMethodTest.php @@ -0,0 +1,112 @@ +quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->getMock(); + $this->address = $this->getMockBuilder(\Magento\Quote\Model\Quote\Address::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->context = $this->createMock(\Magento\Framework\View\Element\Template\Context::class); + $this->configuration = $this->createMock(\Adyen\Hyva\Model\Configuration::class); + $this->methodList = $this->createMock(\Adyen\Hyva\Model\MethodList::class); + $this->session = $this->createMock(\Magento\Checkout\Model\Session::class); + $this->jsonSerializer = $this->createMock(\Magento\Framework\Serialize\Serializer\Json::class); + + $this->paymentMethod = new PaymentMethod( + $this->context, + $this->configuration, + $this->methodList, + $this->session, + $this->jsonSerializer + ); + } + + public function testGetConfiguration() + { + $this->assertInstanceOf(Configuration::class, $this->paymentMethod->getConfiguration()); + } + + public function testGetAvailableMethods() + { + $availableMethods = [ + 'adyen_cc', + 'adyen_googlepay' + ]; + + $this->methodList->expects($this->once()) + ->method('collectAvailableMethods') + ->willReturn($availableMethods); + + $this->assertEquals($availableMethods, $this->paymentMethod->getAvailableMethods()); + } + + public function testGetQuoteShippingAddress() + { + $data = [ + 'some-key' => 'some-value' + ]; + + $this->setQuoteShippingAddressCommmonExpectations(); + + $this->address->expects($this->once())->method('getData')->willReturn($data); + $this->jsonSerializer->expects($this->once())->method('serialize')->willReturn(json_encode($data)); + + $this->assertEquals(json_encode($data), $this->paymentMethod->getQuoteShippingAddress()); + } + + public function testGetQuoteShippingAddressWithException(): void + { + $this->setQuoteShippingAddressCommmonExpectations(); + + $this->address->expects($this->once())->method('getData') + ->willThrowException(new \InvalidArgumentException()); + $this->jsonSerializer->expects($this->once()) + ->method('serialize') + ->willReturn('[]'); + + $this->assertEquals(json_encode([]), $this->paymentMethod->getQuoteShippingAddress()); + } + + private function setQuoteShippingAddressCommmonExpectations() + { + $this->session->expects($this->once())->method('getQuote')->willReturn($this->quote); + $this->quote->expects($this->exactly(2))->method('getShippingAddress')->willReturn($this->address); + } + + + public function testGetQuoteBillingAddress() + { + $data = [ + 'some-key' => 'some-value' + ]; + + $this->session->expects($this->once())->method('getQuote')->willReturn($this->quote); + $this->quote->expects($this->exactly(2))->method('getBillingAddress')->willReturn($this->address); + $this->address->expects($this->once())->method('getData')->willReturn($data); + $this->jsonSerializer->expects($this->once())->method('serialize')->willReturn(json_encode($data)); + + $this->assertEquals(json_encode($data), $this->paymentMethod->getQuoteBillingAddress()); + } +} diff --git a/Test/Unit/Magewire/Checkout/SuccessTest.php b/Test/Unit/Magewire/Checkout/SuccessTest.php new file mode 100644 index 00000000..154deb63 --- /dev/null +++ b/Test/Unit/Magewire/Checkout/SuccessTest.php @@ -0,0 +1,114 @@ +adyenDonations = $this->createMock(AdyenDonationsInterface::class); + $this->adyenGuestDonations = $this->createMock(GuestAdyenDonationsInterface::class); + $this->customerGroupHandler = $this->createMock(CustomerGroupHandler::class); + $this->logger = $this->createMock(LoggerInterface::class); + + $this->success = new Success( + $this->adyenDonations, + $this->adyenGuestDonations, + $this->customerGroupHandler, + $this->logger + ); + } + + public function testUserIsNotGuest() + { + $this->customerGroupHandler->expects($this->once())->method('userIsGuest')->willReturn(false); + + $this->assertFalse($this->success->userIsGuest()); + } + + public function testUserIsGuest() + { + $this->customerGroupHandler->expects($this->once())->method('userIsGuest')->willReturn(true); + + $this->assertTrue($this->success->userIsGuest()); + } + + public function testDonate() + { + $orderId = 123; + $payload = ['some-key' => 'some-value']; + + $this->adyenDonations->expects($this->once()) + ->method('donate'); + + $this->success->donate($orderId, $payload); + + $this->assertTrue($this->success->donationStatus); + } + + public function testDonateFail() + { + $orderId = 123; + $payload = ['some-key' => 'some-value']; + $errorMessage = 'some-error'; + + $this->adyenDonations->expects($this->once()) + ->method('donate') + ->willThrowException(new \Exception($errorMessage)); + + $this->logger->expects($this->once()) + ->method('error') + ->with($errorMessage); + + $this->success->donate($orderId, $payload); + + $this->assertFalse($this->success->donationStatus); + } + + public function testDonateGuest() + { + $maskedCartId = '12344fff'; + $payload = ['some-key' => 'some-value']; + + $this->adyenGuestDonations->expects($this->once()) + ->method('donate'); + + $this->success->donateGuest($maskedCartId, $payload); + + $this->assertTrue($this->success->donationStatus); + } + + public function testDonateGuestFail() + { + $maskedCartId = '12344fff'; + $payload = ['some-key' => 'some-value']; + $errorMessage = 'some-error'; + + $this->adyenGuestDonations->expects($this->once()) + ->method('donate') + ->willThrowException(new \Exception($errorMessage)); + + $this->logger->expects($this->once()) + ->method('error') + ->with($errorMessage); + + $this->success->donateGuest($maskedCartId, $payload); + + $this->assertFalse($this->success->donationStatus); + } +} diff --git a/Test/Unit/Magewire/Payment/Method/CreditCardTest.php b/Test/Unit/Magewire/Payment/Method/CreditCardTest.php new file mode 100644 index 00000000..6a058f1f --- /dev/null +++ b/Test/Unit/Magewire/Payment/Method/CreditCardTest.php @@ -0,0 +1,318 @@ +payment = $this->getMockBuilder(Quote\Payment::class) + ->disableOriginalConstructor() + ->getMock(); + $this->quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->getMock(); + $this->order = $this->getMockBuilder(Order::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->checkoutStateDataValidator = $this->getMockBuilder(CheckoutStateDataValidator::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configuration = $this->getMockBuilder(Configuration::class) + ->disableOriginalConstructor() + ->getMock(); + $this->session = $this->getMockBuilder(\Magento\Checkout\Model\Session::class) + ->disableOriginalConstructor() + ->getMock(); + $this->stateData = $this->getMockBuilder(StateData::class) + ->disableOriginalConstructor() + ->getMock(); + $this->paymentMethods = $this->getMockBuilder(\Adyen\Hyva\Model\PaymentMethod\PaymentMethods::class) + ->disableOriginalConstructor() + ->getMock(); + $this->paymentInformationManagement = $this->getMockBuilder(\Magento\Checkout\Api\PaymentInformationManagementInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->adyenOrderPaymentStatus = $this->getMockBuilder(AdyenOrderPaymentStatusInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->adyenPaymentDetails = $this->getMockBuilder(\Adyen\Payment\Api\AdyenPaymentsDetailsInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerGroupHandler = $this->getMockBuilder(\Adyen\Hyva\Model\Customer\CustomerGroupHandler::class) + ->disableOriginalConstructor() + ->getMock(); + $this->logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->context = new Context( + $this->checkoutStateDataValidator, + $this->configuration, + $this->session, + $this->stateData, + $this->paymentMethods, + $this->paymentInformationManagement, + $this->adyenOrderPaymentStatus, + $this->adyenPaymentDetails, + $this->customerGroupHandler, + $this->logger + ); + + $this->brandsManager = $this->getMockBuilder(BrandsManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->installmentsManager = $this->getMockBuilder(InstallmentsManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->creditCard = new \Adyen\Hyva\Magewire\Payment\Method\CreditCard( + $this->context, + $this->brandsManager, + $this->installmentsManager + ); + } + + public function testGetMethodCode() + { + $this->assertEquals(\Adyen\Hyva\Magewire\Payment\Method\CreditCard::METHOD_CC, $this->creditCard->getMethodCode()); + } + + public function testGetFormattedInstallments() + { + $installments = [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => 'value3', + ]; + + $this->installmentsManager->expects($this->once()) + ->method('getFormattedInstallments') + ->willReturn(json_encode($installments)); + + $result = $this->creditCard->getFormattedInstallments(); + + $this->assertEquals(json_encode($installments), $result); + } + + public function testGetConfiguration() + { + $result = $this->creditCard->getConfiguration(); + + $this->assertInstanceOf(Configuration::class, $result); + } + + public function testPlaceOrder() + { + $data = ['stateData' => []]; + $paymentStatus = 'success'; + $quoteId = '111'; + $orderId = '123'; + + $this->setPlaceOrderCommonExpectations($quoteId); + + $this->paymentInformationManagement->expects($this->once()) + ->method('savePaymentInformationAndPlaceOrder') + ->with($quoteId, $this->payment) + ->willReturn($orderId); + + $this->adyenOrderPaymentStatus->expects($this->once()) + ->method('getOrderPaymentStatus') + ->with($orderId) + ->willReturn($paymentStatus); + + $this->creditCard->placeOrder($data); + + $this->assertEquals($paymentStatus, $this->creditCard->paymentStatus); + } + + public function testPlaceOrderThrowsException() + { + $data = ['stateData' => []]; + $quoteId = '111'; + + $this->setPlaceOrderCommonExpectations($quoteId); + + $this->paymentInformationManagement->expects($this->once()) + ->method('savePaymentInformationAndPlaceOrder') + ->with($quoteId, $this->payment) + ->willThrowException(new \Exception('Some error occurred while placing Order')); + + $this->logger->expects($this->once()) + ->method('error') + ->with('Could not place the Adyen order: Some error occurred while placing Order'); + + $this->creditCard->placeOrder($data); + + $this->assertEquals('{"isRefused":true}', $this->creditCard->paymentStatus); + } + + private function setPlaceOrderCommonExpectations($quoteId) + { + $this->session->expects($this->once()) + ->method('getQuoteId') + ->willReturn($quoteId); + + $this->session->expects($this->once()) + ->method('getQuote') + ->willReturn($this->quote); + + $this->quote->expects($this->once()) + ->method('getPayment') + ->willReturn($this->payment); + } + + public function testEvaluateCompletion() + { + $valuationResultFactory = $this->getMockBuilder(\Hyva\Checkout\Model\Magewire\Component\EvaluationResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $result = $this->creditCard->evaluateCompletion($valuationResultFactory); + + $this->assertInstanceOf(\Hyva\Checkout\Model\Magewire\Component\Evaluation\Success::class, $result); + } + + public function testRefreshProperties() + { + $quoteId = '111'; + $paymentResponse = '{"some-data-structure":["some-values"]}'; + + $this->setRefreshPropertiesCommonExpectations($quoteId); + + $this->paymentMethods->expects($this->once()) + ->method('getData') + ->with($quoteId) + ->willReturn($paymentResponse); + + $this->creditCard->refreshProperties(); + + $this->assertEquals($paymentResponse, $this->creditCard->paymentResponse); + } + + public function testRefreshPropertiesThrowsException() + { + $quoteIdException = '111'; + + $this->setRefreshPropertiesCommonExpectations($quoteIdException); + + $this->paymentMethods->expects($this->once()) + ->method('getData') + ->with($quoteIdException) + ->willThrowException(new \Exception('Some error occurred while refreshing properties')); + + $this->logger->expects($this->once()) + ->method('error') + ->with('Could not collect Adyen payment methods response: Some error occurred while refreshing properties'); + + $this->creditCard->refreshProperties(); + + $this->assertEquals('{}', $this->creditCard->paymentResponse); + } + + private function setRefreshPropertiesCommonExpectations($quoteId) + { + $this->session->expects($this->exactly(2)) + ->method('getQuote') + ->willReturn($this->quote); + + $this->quote->expects($this->once()) + ->method('getShippingAddress'); + + $this->session->expects($this->once()) + ->method('getQuoteId') + ->willReturn($quoteId); + } + + public function testCollectPaymentDetails() + { + $data = [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => 'value3', + ]; + + $orderId = '123'; + $paymentDetails = '{"some-data-structure":[{"some-key":"some-value"}]}'; + + $this->setCollectPaymentDetailsCommonExpectations($orderId); + + $this->adyenPaymentDetails->expects($this->once()) + ->method('initiate') + ->with(json_encode($data), $orderId) + ->willReturn($paymentDetails); + + $this->creditCard->collectPaymentDetails($data); + + $this->assertEquals($paymentDetails, $this->creditCard->paymentDetails); + } + + + public function testCollectPaymentDetailsThrowsException() + { + $data = [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => 'value3', + ]; + $orderId = '123'; + + $this->setCollectPaymentDetailsCommonExpectations($orderId); + + $this->adyenPaymentDetails->expects($this->once()) + ->method('initiate') + ->with(json_encode($data), $orderId) + ->willThrowException(new \Exception('Some error occurred while collecting Payment Details')); + + $this->logger->expects($this->once()) + ->method('error') + ->with('Could not collect payment details: Some error occurred while collecting Payment Details'); + + $this->creditCard->collectPaymentDetails($data); + + $this->assertEquals('{"isRefused":true}', $this->creditCard->paymentDetails); + } + + private function setCollectPaymentDetailsCommonExpectations($orderId) + { + $this->session->expects($this->once()) + ->method('getLastRealOrder') + ->willReturn($this->order); + + $this->order->expects($this->once()) + ->method('getId') + ->willReturn($orderId); + } +} diff --git a/Test/Unit/Model/ConfigurationTest.php b/Test/Unit/Model/ConfigurationTest.php new file mode 100644 index 00000000..965707d4 --- /dev/null +++ b/Test/Unit/Model/ConfigurationTest.php @@ -0,0 +1,87 @@ + + [ + 'adyenCc' => ['isCardRecurringEnabled' => 1], + 'adyen' => ['locale' => 'es_ES'] + ] + ]; + + $this->configProvider = $this->getMockBuilder(CompositeConfigProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $this->dataObjectFactory = $this->getMockBuilder(DataObjectFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->logger = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configProvider->expects($this->exactly(2)) + ->method('getConfig') + ->willReturn($configValues); + + $this->dataObjectFactory->expects($this->once()) + ->method('create') + ->willReturnCallback(function ($data) { + return new \Magento\Framework\DataObject($data['data']); + }); + + $this->configuration = new Configuration( + $this->configProvider, + $this->dataObjectFactory, + $this->logger + ); + } + + public function testGetValue(): void + { + $result = $this->configuration->getValue('adyenCc/isCardRecurringEnabled'); + $this->assertSame(1, $result); + + $result = $this->configuration->getValue('adyen/locale'); + $this->assertSame('es_ES', $result); + + $result = $this->configuration->getValue('nonexistent/path'); + $this->assertNull($result); + } + + public function testGetJsonValue(): void + { + $jsonValue = $this->configuration->getJsonValue('adyenCc/isCardRecurringEnabled'); + $this->assertSame('1', $jsonValue); + + $jsonValue = $this->configuration->getJsonValue('adyen/locale'); + $this->assertSame('"es_ES"', $jsonValue); + + $jsonValue = $this->configuration->getJsonValue('nonexistent/path'); + $this->assertSame('null', $jsonValue); + } + public function testIsCCEnableStoreDetails(): void + { + $result = $this->configuration->isCCEnableStoreDetails(false); + $this->assertTrue($result); + + $result = $this->configuration->isCCEnableStoreDetails(true); + $this->assertFalse($result); + } +} diff --git a/Test/Unit/Model/CreditCard/BrandsManagerTest.php b/Test/Unit/Model/CreditCard/BrandsManagerTest.php new file mode 100644 index 00000000..5cad39cf --- /dev/null +++ b/Test/Unit/Model/CreditCard/BrandsManagerTest.php @@ -0,0 +1,112 @@ +quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->getMock(); + $this->session = $this->getMockBuilder(\Magento\Checkout\Model\Session::class) + ->disableOriginalConstructor() + ->getMock(); + $this->paymentMethods = $this->getMockBuilder(\Adyen\Hyva\Model\PaymentMethod\PaymentMethods::class) + ->disableOriginalConstructor() + ->getMock(); + $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->disableOriginalConstructor() + ->getMock(); + $this->logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->brandsManager = new BrandsManager( + $this->session, + $this->paymentMethods, + $this->serializer, + $this->logger + ); + } + + /** + * @dataProvider inputProviderBrandsManager + */ + public function testGetBrandsAsArrayConsecutive($quoteId, $brands, $brandsSerialized, $paymentMethodsResponse) + { + $this->setExpectations($quoteId, $brands, $brandsSerialized, $paymentMethodsResponse); + + $this->brandsManager->getBrandsAsArray(); + $result = $this->brandsManager->getBrandsAsArray(); + + $this->assertEquals($brands, $result); + } + + /** + * @dataProvider inputProviderBrandsManager + */ + public function testGetBrands($quoteId, $brands, $brandsSerialized, $paymentMethodsResponse) + { + $this->setExpectations($quoteId, $brands, $brandsSerialized, $paymentMethodsResponse, true); + + $this->assertEquals($brandsSerialized, $this->brandsManager->getBrands()); + } + + public function inputProviderBrandsManager(): array + { + return [ + '#1' => [ + 'quoteId' => 456, + 'brands' => ['mc', 'visa'], + 'brandsSerialized' => json_encode(['mc', 'visa']), + 'paymentMethodsResponse' => [ + 'paymentMethodsResponse' => [ + 'paymentMethods' => [ + 'card' => [ + 'type' => 'scheme', + 'brands' => ['mc', 'visa'], + ], + 'somethings_irrelevant' => [ + 'type' => 'somethings_irrelevant', + 'brands' => [], + ], + ] + ] + ] + ] + ]; + } + + private function setExpectations($quoteId, $brands, $brandsSerialized, $paymentMethodsResponse, $serialize = false) + { + $this->session->expects($this->exactly(2)) + ->method('getQuote') + ->willReturn($this->quote); + + $this->quote->expects($this->exactly(2)) + ->method('getId') + ->willReturn($quoteId); + + $this->paymentMethods->expects($this->once()) + ->method('getDataAsArray') + ->with($this->equalTo($quoteId)) + ->willReturn($paymentMethodsResponse); + + $this->serializer->expects($serialize ? $this->once() : $this->never()) + ->method('serialize') + ->with($brands) + ->willReturn($brandsSerialized); + } +} diff --git a/Test/Unit/Model/CreditCard/InstallmentsManagerTest.php b/Test/Unit/Model/CreditCard/InstallmentsManagerTest.php new file mode 100644 index 00000000..3654e263 --- /dev/null +++ b/Test/Unit/Model/CreditCard/InstallmentsManagerTest.php @@ -0,0 +1,83 @@ +session = $this->createMock(\Magento\Checkout\Model\Session::class); + $this->installmentsHelper = $this->createMock(\Adyen\Payment\Helper\Installments::class); + $this->configHelper = $this->createMock(\Adyen\Payment\Helper\Config::class); + $this->storeManager = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); + $this->adyenHelper = $this->createMock(\Adyen\Payment\Helper\Data::class); + $this->adyenLogger = $this->createMock(\Adyen\Payment\Logger\AdyenLogger::class); + + $this->installmentsManager = new InstallmentsManager( + $this->session, + $this->installmentsHelper, + $this->configHelper, + $this->storeManager, + $this->adyenHelper, + $this->adyenLogger + ); + } + + public function testGetFormattedInstallments() + { + $grandTotal = '100.05'; + $quoteData = ['grand_total' => $grandTotal]; + $quote = $this->getMockBuilder(Quote::class)->disableOriginalConstructor()->getMock(); + $store = $this->getMockBuilder(Store::class)->disableOriginalConstructor()->getMock(); + $storeId = 15; + $configData = '{}'; + $ccTypes = ['mc', 'visa']; + $result = '{}'; + + $this->session->expects($this->once()) + ->method('getQuote') + ->willReturn($quote); + + $quote->expects($this->once()) + ->method('getData') + ->willReturn($quoteData); + + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($store); + + $store->expects($this->once()) + ->method('getId') + ->willReturn($storeId); + + $this->configHelper->expects($this->once()) + ->method('getAdyenCcConfigData') + ->with('installments', $storeId) + ->willReturn($configData); + + $this->adyenHelper->expects($this->once()) + ->method('getAdyenCcTypes') + ->willReturn($ccTypes); + + $this->installmentsHelper->expects($this->once()) + ->method('formatInstallmentsConfig') + ->with($configData, $ccTypes, $grandTotal) + ->willReturn($result); + + $this->assertEquals($result, $this->installmentsManager->getFormattedInstallments()); + } +} diff --git a/Test/Unit/Model/Customer/CustomerGroupHandlerTest.php b/Test/Unit/Model/Customer/CustomerGroupHandlerTest.php new file mode 100644 index 00000000..e6a9ac09 --- /dev/null +++ b/Test/Unit/Model/Customer/CustomerGroupHandlerTest.php @@ -0,0 +1,65 @@ +session = $this->getMockBuilder(\Magento\Checkout\Model\Session::class) + ->disableOriginalConstructor() + ->getMock(); + $this->logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->customerGroupHandler = new CustomerGroupHandler( + $this->session, + $this->logger + ); + } + + public function testUserIsGuest() + { + $quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->addMethods(['getCustomerId']) + ->getMock(); + + $this->session->expects($this->once()) + ->method('getQuote') + ->willReturn($quote); + + $quote->expects($this->once()) + ->method('getCustomerId') + ->willReturn(null); + + $this->assertTrue($this->customerGroupHandler->userIsGuest()); + } + + public function testUserIsCustomer() + { + $quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->addMethods(['getCustomerId']) + ->getMock(); + + $this->session->expects($this->once()) + ->method('getQuote') + ->willReturn($quote); + + $quote->expects($this->once()) + ->method('getCustomerId') + ->willReturn(45); + + $this->assertFalse($this->customerGroupHandler->userIsGuest()); + } +} diff --git a/Test/Unit/Model/MethodListTest.php b/Test/Unit/Model/MethodListTest.php new file mode 100644 index 00000000..ea1556d4 --- /dev/null +++ b/Test/Unit/Model/MethodListTest.php @@ -0,0 +1,31 @@ +methodList = new MethodList(); + } + + public function testCollectAvailableMethodsReturnsEmptyArray(): void + { + $this->assertIsArray($this->methodList->collectAvailableMethods()); + $this->assertEmpty($this->methodList->collectAvailableMethods()); + } + + public function testCollectAvailableMethodsReturnsCorrectMethods(): void + { + $methods = ['method1', 'method2']; + $this->methodList = new MethodList($methods); + + $this->assertIsArray($this->methodList->collectAvailableMethods()); + $this->assertCount(2, $this->methodList->collectAvailableMethods()); + $this->assertEquals($methods, $this->methodList->collectAvailableMethods()); + } +} diff --git a/Test/Unit/Model/PaymentMethod/Filter/AdyenBasedTest.php b/Test/Unit/Model/PaymentMethod/Filter/AdyenBasedTest.php new file mode 100644 index 00000000..e6fba7ac --- /dev/null +++ b/Test/Unit/Model/PaymentMethod/Filter/AdyenBasedTest.php @@ -0,0 +1,67 @@ +adyenCc = $this->getMockBuilder(\Magento\Quote\Api\Data\PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + $this->adyenGPay = $this->getMockBuilder(\Magento\Quote\Api\Data\PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + $this->adyenNotSupported = $this->getMockBuilder(\Magento\Quote\Api\Data\PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + + $this->methodList = $this->createMock(\Adyen\Hyva\Model\MethodList::class); + + $this->adyenBased = new AdyenBased($this->methodList); + } + + public function testExecute() + { + $supportedMethods = [ + 'adyen_cc', + 'adyen_googlepay' + ]; + + $list = [ + 'adyen_cc' => $this->adyenCc, + 'adyen_googlepay' => $this->adyenGPay, + 'adyen_unsuported' => $this->adyenNotSupported + ]; + + $this->adyenCc->expects($this->exactly(2))->method('getCode')->willReturn('adyen_cc'); + $this->adyenGPay->expects($this->exactly(2))->method('getCode')->willReturn('adyen_googlepay'); + $this->adyenNotSupported->expects($this->exactly(2))->method('getCode')->willReturn('adyen_unsuported'); + + $this->methodList->expects($this->exactly(3)) + ->method('collectAvailableMethods') + ->willReturn($supportedMethods); + + $result = $this->adyenBased->execute(123, $list); + + $this->assertEquals( + $supportedMethods, + array_keys($result) + ); + + $this->assertArrayNotHasKey('adyen_unsuported', array_keys($result)); + } +} diff --git a/Test/Unit/Model/PaymentMethod/Filter/AdyenConfiguredTest.php b/Test/Unit/Model/PaymentMethod/Filter/AdyenConfiguredTest.php new file mode 100644 index 00000000..f98ae7e0 --- /dev/null +++ b/Test/Unit/Model/PaymentMethod/Filter/AdyenConfiguredTest.php @@ -0,0 +1,79 @@ +adyenCc = $this->getMockBuilder(PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + $this->adyenGPay = $this->getMockBuilder(PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + $this->adyenNotConfigured = $this->getMockBuilder(PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + + $this->paymentMethods = $this->createMock(PaymentMethods::class); + + $this->adyenConfigured = new AdyenConfigured($this->paymentMethods); + } + + public function testExecute() + { + $supportedMethods = [ + 'adyen_cc', + 'adyen_googlepay' + ]; + + $paymentMethods = [ + 'card' => [], + 'googlepay' => [], + 'bmcm' => [] + ]; + + $paymentMethodsResponse = ['paymentMethodsExtraDetails' => $paymentMethods]; + $paymentMethodsResponseSerialized = json_encode($paymentMethodsResponse); + + $list = [ + 'adyen_cc' => $this->adyenCc, + 'adyen_googlepay' => $this->adyenGPay, + 'adyen_not_configured' => $this->adyenNotConfigured + ]; + + $this->adyenCc->expects($this->exactly(2))->method('getCode')->willReturn('adyen_cc'); + $this->adyenGPay->expects($this->exactly(2))->method('getCode')->willReturn('adyen_googlepay'); + $this->adyenNotConfigured->expects($this->exactly(2))->method('getCode')->willReturn('adyen_not_configured'); + + $this->paymentMethods->expects($this->once()) + ->method('getData') + ->willReturn($paymentMethodsResponseSerialized); + + $result = $this->adyenConfigured->execute(123, $list); + + $this->assertEquals( + $supportedMethods, + array_keys($result) + ); + + $this->assertArrayNotHasKey('adyen_not_configured', array_keys($result)); + } +} diff --git a/Test/Unit/Model/PaymentMethod/Filter/ApplePayTest.php b/Test/Unit/Model/PaymentMethod/Filter/ApplePayTest.php new file mode 100644 index 00000000..ae60c558 --- /dev/null +++ b/Test/Unit/Model/PaymentMethod/Filter/ApplePayTest.php @@ -0,0 +1,113 @@ +adyenCc = $this->getMockBuilder(PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + $this->adyenGPay = $this->getMockBuilder(PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + $this->adyenApplePay = $this->getMockBuilder(PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + + $this->http = $this->createMock(Http::class); + + $this->applePay = new ApplePay($this->http); + } + + public function testExecuteWithSafari() + { + $supportedMethods = [ + 'adyen_cc', + 'adyen_googlepay', + 'adyen_applepay' + ]; + + $list = $this->getList(); + + $this->http->expects($this->once()) + ->method('getServerValue') + ->willReturn('something-with-safari-in-it'); + + $this->adyenApplePay->expects($this->never())->method('getCode')->willReturn('adyen_applepay'); + + $result = $this->applePay->execute(123, $list); + + $this->doAssert($supportedMethods, $result); + } + + public function testExecuteWithChrome() + { + $supportedMethods = [ + 'adyen_cc', + 'adyen_googlepay' + ]; + + $this->http->expects($this->once()) + ->method('getServerValue') + ->willReturn('something-with-chrome-and-safari-in-it'); + + $this->adyenApplePay->expects($this->once())->method('getCode')->willReturn('adyen_applepay'); + + $result = $this->applePay->execute(123, $this->getList()); + + $this->doAssert($supportedMethods, $result); + } + + public function testExecuteWithAnythingElse() + { + $supportedMethods = [ + 'adyen_cc', + 'adyen_googlepay' + ]; + + $this->http->expects($this->once()) + ->method('getServerValue') + ->willReturn('something-with-anything-else-in-it'); + + $this->adyenApplePay->expects($this->once())->method('getCode')->willReturn('adyen_applepay'); + + $result = $this->applePay->execute(123, $this->getList()); + + $this->doAssert($supportedMethods, $result); + } + + private function getList(): array + { + return [ + 'adyen_cc' => $this->adyenCc, + 'adyen_googlepay' => $this->adyenGPay, + 'adyen_applepay' => $this->adyenApplePay + ]; + } + + private function doAssert(array $supportedMethods, array $result) + { + $this->assertEquals( + $supportedMethods, + array_keys($result) + ); + } +} diff --git a/Test/Unit/Model/PaymentMethod/Filter/StoredCardsTest.php b/Test/Unit/Model/PaymentMethod/Filter/StoredCardsTest.php new file mode 100644 index 00000000..126f904e --- /dev/null +++ b/Test/Unit/Model/PaymentMethod/Filter/StoredCardsTest.php @@ -0,0 +1,91 @@ +adyenCc = $this->getMockBuilder(\Magento\Quote\Api\Data\PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + $this->adyenGPay = $this->getMockBuilder(\Magento\Quote\Api\Data\PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + $this->adyenCcVault = $this->getMockBuilder(\Magento\Quote\Api\Data\PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['getCode', 'getTitle']) + ->getMock(); + + $this->storedCardsManager = $this->createMock(StoredCardsManager::class); + + $this->storedCards = new StoredCards($this->storedCardsManager); + } + + public function testExecuteWhenNoStoredCardsAreNotFound() + { + $supportedMethods = [ + 'adyen_cc', + 'adyen_googlepay', + ]; + + $this->adyenCcVault->expects($this->once())->method('getCode')->willReturn('adyen_cc_vault'); + + $this->storedCardsManager->expects($this->once()) + ->method('getStoredCards') + ->willReturn([]); + + $result = $this->storedCards->execute(123, $this->getList()); + + $this->assertEquals( + $supportedMethods, + array_keys($result) + ); + + $this->assertArrayNotHasKey('adyen_cc_vault', array_keys($result)); + } + + public function testExecuteWhenNoStoredCardsAreFound() + { + $supportedMethods = [ + 'adyen_cc', + 'adyen_googlepay', + 'adyen_cc_vault', + ]; + + $this->adyenCcVault->expects($this->never())->method('getCode')->willReturn('adyen_cc_vault'); + + $this->storedCardsManager->expects($this->once()) + ->method('getStoredCards') + ->willReturn(['vaultCardA', 'vaultCardB']); + + $result = $this->storedCards->execute(123, $this->getList()); + + $this->assertEquals( + $supportedMethods, + array_keys($result) + ); + } + + private function getList(): array + { + return [ + 'adyen_cc' => $this->adyenCc, + 'adyen_googlepay' => $this->adyenGPay, + 'adyen_cc_vault' => $this->adyenCcVault + ]; + } +} diff --git a/Test/Unit/Model/PaymentMethod/PaymentMethodsTest.php b/Test/Unit/Model/PaymentMethod/PaymentMethodsTest.php new file mode 100644 index 00000000..55be5bfa --- /dev/null +++ b/Test/Unit/Model/PaymentMethod/PaymentMethodsTest.php @@ -0,0 +1,120 @@ +adyenPaymentMethods = $this->getMockBuilder(\Adyen\Payment\Helper\PaymentMethods::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->disableOriginalConstructor() + ->getMock(); + $this->logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->paymentMethods = new PaymentMethods( + $this->adyenPaymentMethods, + $this->serializer, + $this->logger + ); + } + + /** + * @dataProvider inputProviderPaymentMethods + */ + public function testGetDataAsArrayConsecutive($quoteId, $brands, $brandsSerialized, $paymentMethodsResponse) + { + $this->setExpectations($paymentMethodsResponse); + + $this->paymentMethods->getDataAsArray($quoteId); + $result = $this->paymentMethods->getDataAsArray($quoteId); + + $this->assertEquals($paymentMethodsResponse, $result); + } + + public function testGetDataAsArrayWhenExceptionIsThrownFromAdyenPaymentMethods() + { + $quoteId = 123; + $exceptionMessage = 'An error occurred from Adyen endpoint'; + $exception = new \Exception($exceptionMessage); + + $this->adyenPaymentMethods->expects($this->once()) + ->method('getPaymentMethods') + ->willThrowException($exception); + + $this->logger->expects($this->once()) + ->method('error') + ->with('Could not fetch adyen payment methods: ' . $exceptionMessage); + + $this->assertEquals([], $this->paymentMethods->getDataAsArray($quoteId)); + } + + /** + * @dataProvider inputProviderPaymentMethods + */ + public function testGetDataConsecutive($quoteId, $brands, $brandsSerialized, $paymentMethodsResponse) + { + $this->setExpectations($paymentMethodsResponse, true); + + $this->paymentMethods->getData($quoteId); + $result = $this->paymentMethods->getData($quoteId); + + $this->assertEquals(json_encode($paymentMethodsResponse), $result); + } + + public function inputProviderPaymentMethods(): array + { + return [ + '#1' => [ + 'quoteId' => 123, + 'brands' => ['mc', 'visa'], + 'brandsSerialized' => json_encode(['mc', 'visa']), + 'paymentMethodsResponse' => [ + 'paymentMethodsResponse' => [ + 'paymentMethods' => [ + 'card' => [ + 'type' => 'scheme', + 'brands' => ['mc', 'visa'], + ], + 'somethings_else' => [ + 'type' => 'something_else', + 'brands' => [], + ], + ] + ] + ] + ] + ]; + } + + private function setExpectations($paymentMethodsResponse, $serialize = false) + { + $this->adyenPaymentMethods->expects($this->once()) + ->method('getPaymentMethods') + ->willReturn(json_encode($paymentMethodsResponse)); + + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with(json_encode($paymentMethodsResponse)) + ->willReturn($paymentMethodsResponse); + + $this->serializer->expects($serialize ? $this->once() : $this->never()) + ->method('serialize') + ->with($paymentMethodsResponse) + ->willReturn(json_encode($paymentMethodsResponse)); + } +} diff --git a/Test/Unit/Observer/InstallmentsDataAssignerTest.php b/Test/Unit/Observer/InstallmentsDataAssignerTest.php new file mode 100644 index 00000000..e95412eb --- /dev/null +++ b/Test/Unit/Observer/InstallmentsDataAssignerTest.php @@ -0,0 +1,72 @@ +session = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->addMethods(['getNumberOfInstallments', 'getCcType']) + ->getMock(); + $this->logger = $this->createMock(LoggerInterface::class); + $this->observer = $this->createMock(Observer::class); + $this->event = $this->getMockBuilder(Event::class) + ->onlyMethods(['getDataByKey']) + ->getMock(); + + $this->installmentsDataAssigner = new InstallmentsDataAssigner($this->session, $this->logger); + } + + public function testUpdateAdditionalInformation() + { + $additionalInformation = []; + $numberOfInstallments = 4; + $ccType = 'mc'; + $additionalInformationUpdated = $additionalInformation; + $additionalInformationUpdated['number_of_installments'] = $numberOfInstallments; + $additionalInformationUpdated['cc_type'] = $ccType; + + $payment = $this->getMockBuilder(Payment::class)->disableOriginalConstructor()->getMock(); + + $this->observer->method('getEvent')->willReturn($this->event); + $this->event->method('getDataByKey') + ->with('payment_model') + ->willReturn($payment); + + $this->session->expects($this->exactly(2)) + ->method('getNumberOfInstallments') + ->willReturn($numberOfInstallments); + + $this->session->expects($this->exactly(2)) + ->method('getCcType') + ->willReturn($ccType); + + $payment->expects($this->once()) + ->method('getAdditionalInformation') + ->willReturn($additionalInformation); + + $payment->expects($this->once()) + ->method('setAdditionalInformation') + ->with($additionalInformationUpdated); + + $this->installmentsDataAssigner->execute($this->observer); + } +} diff --git a/Test/Unit/Observer/PaymentTokenAssignerTest.php b/Test/Unit/Observer/PaymentTokenAssignerTest.php new file mode 100644 index 00000000..da276aa2 --- /dev/null +++ b/Test/Unit/Observer/PaymentTokenAssignerTest.php @@ -0,0 +1,97 @@ +session = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->addMethods(['getStoredCardPublicHash']) + ->getMock(); + $this->paymentTokenManagement = $this->createMock(\Magento\Vault\Api\PaymentTokenManagementInterface::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->observer = $this->createMock(Observer::class); + $this->event = $this->getMockBuilder(Event::class) + ->onlyMethods(['getDataByKey']) + ->getMock(); + + $this->paymentTokenAssigner = new PaymentTokenAssigner( + $this->session, + $this->paymentTokenManagement, + $this->logger + ); + } + + public function testUpdateAdditionalInformation() + { + $additionalInformation = []; + $tokenPublicHash = '2525kkkk'; + $paymentToken = '6777kkk'; + $customerId = 123; + $additionalInformationUpdated = $additionalInformation; + $additionalInformationUpdated[PaymentTokenInterface::PUBLIC_HASH] = $tokenPublicHash; + $additionalInformationUpdated[PaymentTokenInterface::CUSTOMER_ID] = $customerId; + + $payment = $this->getMockBuilder(Payment::class)->disableOriginalConstructor()->getMock(); + $quote = $this->getMockBuilder(Quote::class)->disableOriginalConstructor()->getMock(); + $customer = $this->getMockBuilder(Customer::class)->disableOriginalConstructor()->getMock(); + + $this->observer->method('getEvent')->willReturn($this->event); + $this->event->method('getDataByKey') + ->with('payment_model') + ->willReturn($payment); + + $this->session->expects($this->once()) + ->method('getStoredCardPublicHash') + ->willReturn($tokenPublicHash); + + $payment->expects($this->once()) + ->method('getQuote') + ->willReturn($quote); + + $quote->expects($this->once()) + ->method('getCustomer') + ->willReturn($customer); + + $customer->expects($this->once()) + ->method('getId') + ->willReturn($customerId); + + $this->paymentTokenManagement->expects($this->once()) + ->method('getByPublicHash') + ->with($tokenPublicHash, $customerId) + ->willReturn($paymentToken); + + $payment->expects($this->once()) + ->method('getAdditionalInformation') + ->willReturn($additionalInformation); + + $payment->expects($this->once()) + ->method('setAdditionalInformation') + ->with($additionalInformationUpdated); + + $this->paymentTokenAssigner->execute($this->observer); + } +} diff --git a/Test/Unit/Plugin/InitMethodsTest.php b/Test/Unit/Plugin/InitMethodsTest.php new file mode 100644 index 00000000..5a19a98d --- /dev/null +++ b/Test/Unit/Plugin/InitMethodsTest.php @@ -0,0 +1,75 @@ +paymentMethodFilter = $this->createMock(FilterInterface::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->subject = $this->createMock(PaymentMethodManagementInterface::class); + + $this->initMethods = new InitMethods($this->paymentMethodFilter, $this->logger); + } + + public function testAfterGetListIsFiltered(): void + { + $quoteId = 123; + $paymentMethods = ['payment_method_1', 'payment_method_2', 'payment_method_3']; + $filteredMethods = ['payment_method_1', 'payment_method_2']; + + $this->paymentMethodFilter->expects($this->once()) + ->method('execute') + ->with($quoteId, $paymentMethods) + ->willReturn($filteredMethods); + + $result = $this->initMethods->afterGetList($this->subject, $paymentMethods, $quoteId); + + $this->assertEquals($filteredMethods, $result); + } + + public function testMethodFilterThrowsExceptionListRemainsUnchanged(): void + { + $quoteId = 123; + $paymentMethods = ['payment_method_1', 'payment_method_2', 'payment_method_3']; + + $this->paymentMethodFilter->method('execute') + ->willThrowException(new \Exception('Localized problem X.')); + + $this->logger->expects($this->once()) + ->method('error') + ->with('Error during filtering available methods: Localized problem X.'); + + $result = $this->initMethods->afterGetList($this->subject, $paymentMethods, $quoteId); + + $this->assertEquals($paymentMethods, $result); + } +} From c8a27114f3fd60c1aa99eb37bbf3e348692f5bb7 Mon Sep 17 00:00:00 2001 From: Khushboo Date: Tue, 21 May 2024 16:52:41 +0200 Subject: [PATCH 39/40] [ECP-9063] Preparing release candidate (#40) * [ECP-9063] RC Release preparation - Adding .github directory and related files * [ECP-9063] RC Release preparation - removing version from composer.json, as we will have release candidate release * [ECP-9063] RC Release preparation - Adding correct version of module-payment that will support hyva --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/bug_report.md | 44 ++++++++++++++++++++++++++++ .github/release.yml | 14 +++++++++ composer.json | 3 +- 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/release.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..4d4d1c6d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Adyen/plugin-developers diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..7858ceb3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,44 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: Bug report +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Magento version** +[e.g. 2.4.7] + +**Plugin version** +[e.g. 1.0.0] + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] + +**Smartphone (please complete the following information):** +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..0cd34a7d --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,14 @@ +changelog: + categories: + - title: Breaking Changes 🛠 + labels: + - Breaking change + - title: New Features 💎 + labels: + - Feature + - title: Fixes ⛑️ + labels: + - Fix + - title: Other Changes 🖇️ + labels: + - "*" diff --git a/composer.json b/composer.json index e880631d..1d03492f 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,9 @@ { "name": "adyen/module-hyva-checkout", "description": "Adyen Integration with Hyva Checkout", - "version": "100.0.0", "type": "magento2-module", "require": { - "adyen/module-payment": "^9.5.0", + "adyen/module-payment": "^9.5.2", "hyva-themes/magento2-default-theme": "^1.3" }, "autoload": { From 157eefecc009cd8c707ca3cc1af721f3acff9aff Mon Sep 17 00:00:00 2001 From: Peter Ojo Date: Wed, 22 May 2024 12:48:07 +0200 Subject: [PATCH 40/40] add license in composer --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 1d03492f..137ad6f3 100644 --- a/composer.json +++ b/composer.json @@ -2,6 +2,7 @@ "name": "adyen/module-hyva-checkout", "description": "Adyen Integration with Hyva Checkout", "type": "magento2-module", + "license": "MIT", "require": { "adyen/module-payment": "^9.5.2", "hyva-themes/magento2-default-theme": "^1.3"