diff --git a/Block/Template.php b/Block/Template.php new file mode 100644 index 00000000..42f00c0a --- /dev/null +++ b/Block/Template.php @@ -0,0 +1,168 @@ +adyenHyvaConfigProvider = $adyenHyvaConfigProvider; + $this->paymentMethodBlockFactory = $paymentMethodBlockFactory; + $this->paymentMethodWireFactory = $paymentMethodWireFactory; + $this->methodList = $methodList; + } + + /** + * Overrides parent method to include Adyen payment methods + * + * @return Template + * @throws LocalizedException + */ + public function _prepareLayout() + { + $this->renderAdyenPaymentMethods(); + + return parent::_prepareLayout(); + } + + /** + * Render available payment methods + * + * @return void + * @throws LocalizedException + */ + private function renderAdyenPaymentMethods(): void + { + $methods = $this->methodList->collectAvailableMethods(); + /** @var PaymentMethodBlock[] $paymentMethodBlocks */ + $paymentMethodBlocks = []; + + foreach ($methods as $method) { + /** @var PaymentMethodBlock $paymentMethodBlock */ + $paymentMethodBlock = $this->paymentMethodBlockFactory->create(); + + if ($this->methodList->getCustomMagewireClass($method)) { + $paymentMethodBlock->setWire($this->methodList->getCustomMagewireClass($method)); + } else { + /** @var AbstractPaymentMethodWire $paymentMethodWire */ + $paymentMethodWire = $this->paymentMethodWireFactory->create(); + $paymentMethodWire->setMethodCode($method); + + $paymentMethodBlock->setWire($paymentMethodWire); + } + + $paymentMethodBlock->setMethodName($method); + $paymentMethodBlock->setBlockName( + $this->generateBlockNameFromPaymentMethodName($method) + ); + $paymentMethodBlock->setTemplate( + $this->getPaymentMethodTemplate($method) + ); + + $paymentMethodBlocks[] = $paymentMethodBlock; + } + + foreach ($paymentMethodBlocks as $paymentMethodBlock) { + $this->createPaymentMethodBlock($paymentMethodBlock); + } + } + + /** + * Creates the payment method block in the checkout layout + * + * @param PaymentMethodBlock $paymentMethodBlock + * @return void + * @throws LocalizedException + */ + private function createPaymentMethodBlock(PaymentMethodBlock $paymentMethodBlock): void + { + $layout = $this->getLayout(); + + if (!array_key_exists($paymentMethodBlock->getBlockName(), $layout->getAllBlocks())) { + $block = $layout->createBlock( + \Magento\Framework\View\Element\Template::class, + $paymentMethodBlock->getBlockName() + ); + $block->setTemplate($paymentMethodBlock->getTemplate()); + $block->setData(self::MAGEWIRE, $paymentMethodBlock->getWire()); + + $layout->setChild( + self::PARENT_PAYMENT_METHODS_BLOCK, + $paymentMethodBlock->getBlockName(), + $paymentMethodBlock->getMethodName() + ); + } + } + + /** + * Generates the payment method block name from the given method name + * + * @param string $paymentMethodName + * @return string + */ + private function generateBlockNameFromPaymentMethodName(string $paymentMethodName): string + { + return sprintf('%s.%s', self::PARENT_PAYMENT_METHODS_BLOCK, $paymentMethodName); + } + + /** + * Builds template file depending on the custom renderer requirement. + * + * @param string $paymentMethodName + * @return string + */ + private function getPaymentMethodTemplate(string $paymentMethodName): string + { + if ($this->adyenHyvaConfigProvider->isCustomRendererRequired($paymentMethodName)) { + $template = $this->methodList->getCustomMethodRenderer($paymentMethodName); + } else { + $template = self::DEFAULT_ADYEN_PAYMENT_METHOD_TEMPLATE; + } + + return sprintf('%s/%s', self::TEMPLATE_DIR, $template); + } +} diff --git a/Magewire/Payment/Method/AbstractPaymentMethodWire.php b/Magewire/Payment/Method/AbstractPaymentMethodWire.php new file mode 100644 index 00000000..df260df0 --- /dev/null +++ b/Magewire/Payment/Method/AbstractPaymentMethodWire.php @@ -0,0 +1,49 @@ +createValidation('validate-adyen-component-state'); + } + + /** + * @return string + */ + public function getMethodCode(): string + { + return $this->methodCode; + } + + /** + * @param string $methodCode + * @return $this + */ + public function setMethodCode(string $methodCode): AbstractPaymentMethodWire + { + $this->methodCode = $methodCode; + + return $this; + } + + public function getContainerName(): string + { + return str_replace('-', '', $this->getMethodCode()); + } +} diff --git a/Magewire/Payment/Method/ApplePay.php b/Magewire/Payment/Method/ApplePay.php deleted file mode 100644 index b016695c..00000000 --- a/Magewire/Payment/Method/ApplePay.php +++ /dev/null @@ -1,30 +0,0 @@ -createBlocking(); - } -} diff --git a/Magewire/Payment/Method/GooglePay.php b/Magewire/Payment/Method/GooglePay.php deleted file mode 100644 index 163f1fc4..00000000 --- a/Magewire/Payment/Method/GooglePay.php +++ /dev/null @@ -1,30 +0,0 @@ -createBlocking(); - } -} diff --git a/Magewire/Payment/Method/Klarna.php b/Magewire/Payment/Method/Klarna.php deleted file mode 100644 index 1a7739fe..00000000 --- a/Magewire/Payment/Method/Klarna.php +++ /dev/null @@ -1,30 +0,0 @@ -createBlocking(); - } -} diff --git a/Magewire/Payment/Method/Paypal.php b/Magewire/Payment/Method/Paypal.php deleted file mode 100644 index e7522f3f..00000000 --- a/Magewire/Payment/Method/Paypal.php +++ /dev/null @@ -1,30 +0,0 @@ -createBlocking(); - } -} diff --git a/Model/MethodList.php b/Model/MethodList.php index 5e85211b..0cf80931 100644 --- a/Model/MethodList.php +++ b/Model/MethodList.php @@ -4,11 +4,39 @@ namespace Adyen\Hyva\Model; +use Adyen\Hyva\Magewire\Payment\Method\AdyenPaymentComponent; +use Adyen\Hyva\Model\Ui\AdyenHyvaConfigProvider; + class MethodList { + /** + * @var AdyenHyvaConfigProvider + */ + private AdyenHyvaConfigProvider $adyenHyvaConfigProvider; + + /** + * @var array + */ + public array $customMethodRenderers; + + /** + * @var array + */ + public array $customMagewireClasses; + + /** + * @param AdyenHyvaConfigProvider $adyenHyvaConfigProvider + * @param array $customMethodRenderers + * @param array $customMagewireClasses + */ public function __construct( - private $availableMethods = [] + AdyenHyvaConfigProvider $adyenHyvaConfigProvider, + array $customMethodRenderers = [], + array $customMagewireClasses = [] ) { + $this->adyenHyvaConfigProvider = $adyenHyvaConfigProvider; + $this->customMethodRenderers = $customMethodRenderers; + $this->customMagewireClasses = $customMagewireClasses; } /** @@ -16,6 +44,44 @@ public function __construct( */ public function collectAvailableMethods(): array { - return $this->availableMethods; + $paymentMethods = array_keys($this->adyenHyvaConfigProvider->getPaymentMethodTxVariants()); + $availableMethods = []; + + foreach ($paymentMethods as $paymentMethod) { + $available = true; + + if ($this->adyenHyvaConfigProvider->isCustomRendererRequired($paymentMethod) && + !isset($this->customMethodRenderers[$paymentMethod])) { + $available = false; + } + + if ($available) { + $availableMethods[] = $paymentMethod; + } + } + + return array_values(array_merge($availableMethods, array_keys($this->customMagewireClasses))); + } + + /** + * Returns the custom method renderer defined in di.xml + * + * @param string $methodCode + * @return string|null + */ + public function getCustomMethodRenderer(string $methodCode): ?string + { + return $this->customMethodRenderers[$methodCode] ?? null; + } + + /** + * Checks if the payment method has a statically rendered layout block + * + * @param string $methodCode + * @return string|null + */ + public function getCustomMagewireClass(string $methodCode): ?AdyenPaymentComponent + { + return $this->customMagewireClasses[$methodCode] ?? null; } } diff --git a/Model/PaymentMethod/Filter/ApplePay.php b/Model/PaymentMethod/Filter/ApplePay.php index 46e5b647..afd0d426 100644 --- a/Model/PaymentMethod/Filter/ApplePay.php +++ b/Model/PaymentMethod/Filter/ApplePay.php @@ -2,7 +2,6 @@ namespace Adyen\Hyva\Model\PaymentMethod\Filter; -use Adyen\Hyva\Magewire\Payment\Method\ApplePay as ApplePayComponent; use Magento\Framework\App\Request\Http as HttpRequest; /** @@ -10,6 +9,8 @@ */ class ApplePay implements FilterInterface { + const METHOD_APPLE_PAY = 'adyen_applepay'; + public function __construct( private readonly HttpRequest $httpRequest ) { @@ -27,7 +28,7 @@ public function execute(int $quoteId, array $list): array } foreach ($list as $key => $method) { - if ($method->getCode() == ApplePayComponent::METHOD_APPLE_PAY) { + if ($method->getCode() == self::METHOD_APPLE_PAY) { unset($list[$key]); } } diff --git a/Model/PaymentMethodBlock.php b/Model/PaymentMethodBlock.php new file mode 100644 index 00000000..43b6ab10 --- /dev/null +++ b/Model/PaymentMethodBlock.php @@ -0,0 +1,106 @@ +methodName; + } + + /** + * @param string $methodName + * @return $this + */ + public function setMethodName(string $methodName): PaymentMethodBlock + { + $this->methodName = $methodName; + + return $this; + } + + /** + * @return string + */ + public function getBlockName(): string + { + return $this->blockName; + } + + /** + * @param string $blockName + * @return $this + */ + public function setBlockName(string $blockName): PaymentMethodBlock + { + $this->blockName = $blockName; + + return $this; + } + + /** + * @return string + */ + public function getTemplate(): string + { + return $this->template; + } + + /** + * @param string $template + * @return $this + */ + public function setTemplate(string $template): PaymentMethodBlock + { + $this->template = $template; + + return $this; + } + + /** + * @return EvaluationInterface + */ + public function getWire(): EvaluationInterface + { + return $this->wire; + } + + /** + * @param EvaluationInterface $wire + * @return $this + */ + public function setWire(EvaluationInterface $wire): PaymentMethodBlock + { + $this->wire = $wire; + + return $this; + } +} diff --git a/Model/Ui/AdyenHyvaConfigProvider.php b/Model/Ui/AdyenHyvaConfigProvider.php new file mode 100644 index 00000000..4b070d21 --- /dev/null +++ b/Model/Ui/AdyenHyvaConfigProvider.php @@ -0,0 +1,43 @@ +txVariants; + } + + /** + * Check whether given payment method requires a custom renderer or not + * + * @param string $methodName + * @return bool + */ + public function isCustomRendererRequired(string $methodName): bool + { + $customMethodRenderers = $this->getCustomMethodRenderers(); + + return key_exists($methodName, $customMethodRenderers); + } + + /** + * Returns the list of payment methods which require custom method renderers + * + * @return array + */ + private function getCustomMethodRenderers(): array + { + return $this->customMethodRenderers; + } +} diff --git a/README.md b/README.md index cc8a2dee..fcc45783 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This module depends on: The dependencies may be obtained like for example ``` - "adyen/module-payment": "9.2.0", + "adyen/module-payment": "^9.6.1", "hyva-themes/magento2-default-theme": "^1.3", "hyva-themes/magento2-hyva-checkout": "^1.1", ``` @@ -30,20 +30,4 @@ Then, the setup requires that for a given store, the Hyva theme and the Hyva che - Navigate to the Stores > Configuration > Hyva Themes > Checkout > General and activate `Hyva Default` (or `Hyva One page`) for a given store view ### Supported methods -The following payment methods are supported: - - - Credit card - - Stored (Tokenized) credit card - - Google pay - - Apple Pay - - Paypal - -### 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`). +Please refer to [Adobe Commerce Supported Payment Methods](https://docs.adyen.com/plugins/adobe-commerce/supported-payment-methods/) documentation. diff --git a/composer.json b/composer.json index 137ad6f3..a8276376 100644 --- a/composer.json +++ b/composer.json @@ -2,10 +2,12 @@ "name": "adyen/module-hyva-checkout", "description": "Adyen Integration with Hyva Checkout", "type": "magento2-module", + "version": "1.0.0", "license": "MIT", "require": { - "adyen/module-payment": "^9.5.2", - "hyva-themes/magento2-default-theme": "^1.3" + "adyen/module-payment": "^9.6.1", + "hyva-themes/magento2-default-theme": "^1.3", + "hyva-themes/magento2-hyva-checkout": "^1.1" }, "autoload": { "files": [ diff --git a/etc/di.xml b/etc/di.xml index f8d74bec..130c016a 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -6,23 +6,26 @@ - + - - adyen_cc - adyen_googlepay - adyen_applepay - adyen_paypal - adyen_cc_vault - adyen_klarna + + Adyen\Hyva\Model\CheckoutSession\ResetHandler\QuoteStatus - + - - Adyen\Hyva\Model\CheckoutSession\ResetHandler\QuoteStatus + + adyen-cc-method.phtml + adyen-applepay-method.phtml + adyen-googlepay-method.phtml + adyen-paypal-method.phtml + adyen-cashapp-method.phtml + adyen-affirm-method.phtml + + + Adyen\Hyva\Magewire\Payment\Method\CreditCard diff --git a/view/frontend/layout/hyva_checkout_components.xml b/view/frontend/layout/hyva_checkout_components.xml index 49655db6..e7cdbbaa 100644 --- a/view/frontend/layout/hyva_checkout_components.xml +++ b/view/frontend/layout/hyva_checkout_components.xml @@ -3,7 +3,9 @@ - + Adyen\Hyva\Magewire\Payment\MethodList @@ -13,46 +15,6 @@ class="Adyen\Hyva\Block\StoredCards" template="Adyen_Hyva::checkout/payment/method-list/stored-cards.phtml"> - - - - Adyen\Hyva\Magewire\Payment\Method\CreditCard - - - - - - Adyen\Hyva\Magewire\Payment\Method\GooglePay - - - - - - Adyen\Hyva\Magewire\Payment\Method\ApplePay - - - - - - Adyen\Hyva\Magewire\Payment\Method\Paypal - - - - - - Adyen\Hyva\Magewire\Payment\Method\Klarna - - diff --git a/view/frontend/templates/payment/method-renderer/adyen-affirm-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-affirm-method.phtml new file mode 100644 index 00000000..2b35a4c0 --- /dev/null +++ b/view/frontend/templates/payment/method-renderer/adyen-affirm-method.phtml @@ -0,0 +1,88 @@ + + +
+
+ + +
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 9102e067..a21b54bf 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-applepay-method.phtml @@ -1,12 +1,12 @@ @@ -18,12 +18,11 @@ use Adyen\Hyva\Magewire\Payment\Method\ApplePay; buildConfiguration (paymentMethod, paymentMethodsExtraInfo) { let baseComponentConfiguration = super.buildConfiguration(paymentMethod, paymentMethodsExtraInfo); - let applePayConfiguration = Object.assign(baseComponentConfiguration, paymentMethodsExtraInfo[paymentMethod.type].configuration); - applePayConfiguration.showPayButton = true; - applePayConfiguration.totalPriceLabel = baseComponentConfiguration.configuration.merchantName; - applePayConfiguration.code = "adyen_applepay"; + baseComponentConfiguration.showPayButton = true; + baseComponentConfiguration.totalPriceLabel = baseComponentConfiguration.configuration.merchantName; + baseComponentConfiguration.code = "adyen_applepay"; - return applePayConfiguration + return baseComponentConfiguration } } @@ -38,7 +37,7 @@ use Adyen\Hyva\Magewire\Payment\Method\ApplePay; async function init(methodCode) { try { - let wire = Magewire.find('checkout.payment.method.' + methodCode); + let wire = Magewire.find('checkout.payment.methods.' + methodCode); wire.refreshProperties() .then(() => { let applePayHandler = new applePayComponentHandler( diff --git a/view/frontend/templates/payment/method-renderer/adyen-cashapp-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-cashapp-method.phtml new file mode 100644 index 00000000..706baab4 --- /dev/null +++ b/view/frontend/templates/payment/method-renderer/adyen-cashapp-method.phtml @@ -0,0 +1,85 @@ + + +
+
+ + +
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 5d11f163..de383e0d 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-cc-method.phtml @@ -25,7 +25,7 @@ use Adyen\Hyva\Magewire\Payment\Method\CreditCard; async function init(methodCode) { try { - let wire = Magewire.find('checkout.payment.method.' + methodCode); + let wire = Magewire.find('checkout.payment.methods.' + methodCode); wire.refreshProperties() .then(() => { let creditCardHandler = new componentHandler( diff --git a/view/frontend/templates/payment/method-renderer/adyen-default-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-default-method.phtml new file mode 100644 index 00000000..e0bacfe4 --- /dev/null +++ b/view/frontend/templates/payment/method-renderer/adyen-default-method.phtml @@ -0,0 +1,75 @@ + + +
+
+ + +
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 797bddb1..a8b27c20 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-googlepay-method.phtml @@ -1,12 +1,12 @@ @@ -17,11 +17,9 @@ use Adyen\Hyva\Magewire\Payment\Method\GooglePay; class googlePayComponentHandler extends componentHandler { buildConfiguration (paymentMethod, paymentMethodsExtraInfo) { let baseComponentConfiguration = super.buildConfiguration(paymentMethod, paymentMethodsExtraInfo); + baseComponentConfiguration.showPayButton = true; - let googlePayConfiguration = Object.assign(baseComponentConfiguration, paymentMethodsExtraInfo[paymentMethod.type].configuration); - googlePayConfiguration.showPayButton = true; - - return googlePayConfiguration + return baseComponentConfiguration; } } @@ -36,7 +34,7 @@ use Adyen\Hyva\Magewire\Payment\Method\GooglePay; async function init(methodCode) { try { - let wire = Magewire.find('checkout.payment.method.' + methodCode); + let wire = Magewire.find('checkout.payment.methods.' + methodCode); wire.refreshProperties() .then(() => { let googlePayHandler = new googlePayComponentHandler( diff --git a/view/frontend/templates/payment/method-renderer/adyen-klarna-method.phtml b/view/frontend/templates/payment/method-renderer/adyen-klarna-method.phtml deleted file mode 100644 index 31a98399..00000000 --- a/view/frontend/templates/payment/method-renderer/adyen-klarna-method.phtml +++ /dev/null @@ -1,66 +0,0 @@ - - -
-
- - -
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 5f9533fe..3fabd46f 100644 --- a/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml +++ b/view/frontend/templates/payment/method-renderer/adyen-paypal-method.phtml @@ -1,12 +1,12 @@ @@ -17,10 +17,9 @@ use Adyen\Hyva\Magewire\Payment\Method\Paypal; class paypalComponentHandler extends componentHandler { buildConfiguration (paymentMethod, paymentMethodsExtraInfo) { let baseComponentConfiguration = super.buildConfiguration(paymentMethod, paymentMethodsExtraInfo); - let paypalConfiguration = Object.assign(baseComponentConfiguration, paymentMethodsExtraInfo[paymentMethod.type].configuration); - paypalConfiguration.showPayButton = true; + baseComponentConfiguration.showPayButton = true; - return paypalConfiguration + return baseComponentConfiguration; } } @@ -35,7 +34,7 @@ use Adyen\Hyva\Magewire\Payment\Method\Paypal; async function init(methodCode) { try { - let wire = Magewire.find('checkout.payment.method.' + methodCode); + let wire = Magewire.find('checkout.payment.methods.' + methodCode); wire.refreshProperties() .then(() => { let paypalHandler = new paypalComponentHandler( diff --git a/view/frontend/templates/payment/model/adyen-payment-method.phtml b/view/frontend/templates/payment/model/adyen-payment-method.phtml index 601dc687..d22db25e 100644 --- a/view/frontend/templates/payment/model/adyen-payment-method.phtml +++ b/view/frontend/templates/payment/model/adyen-payment-method.phtml @@ -198,8 +198,8 @@ $billingAddress = $block->getQuoteBillingAddress(); let paymentMethodConfiguration = self.collectPaymentMethodConfiguration( paymentMethods, - methodCode.split("_").pop() - ); + methodCode.replace('adyen_', '') + ) if (paymentMethodConfiguration !== null) { let configuration = self.buildConfiguration( @@ -225,7 +225,7 @@ $billingAddress = $block->getQuoteBillingAddress(); paymentMethods.paymentMethodsResponse ); - self.mountComponent(component, paymentMethodConfiguration.type, configuration); + await self.mountComponent(component, paymentMethodConfiguration.type, configuration); hyvaCheckout.payment.activate(methodCode, { @@ -239,8 +239,6 @@ $billingAddress = $block->getQuoteBillingAddress(); }, document.getElementById(element) ); - - hyvaCheckout.navigation.enableButtonPlaceOrder(); } } else { self.renderMethodUnavailableMessage(); @@ -274,11 +272,14 @@ $billingAddress = $block->getQuoteBillingAddress(); let configuration = { ...paymentMethod, showPayButton: showPayButton, - countryCode: formattedShippingAddress.country_id ? formattedShippingAddress.country_id : formattedBillingAddress.country_id, - data: {} + countryCode: formattedShippingAddress.country_id ? formattedShippingAddress.country_id : formattedBillingAddress.country_id }; - return configuration + if (!!paymentMethodsExtraInfo[paymentMethod.type].configuration) { + return Object.assign(configuration, paymentMethodsExtraInfo[paymentMethod.type].configuration) + } else { + return configuration; + } } async buildComponent( @@ -361,7 +362,6 @@ $billingAddress = $block->getQuoteBillingAddress(); if (responseJSON.isRefused) { self.renderMessage(""); - hyvaCheckout.navigation.enableButtonPlaceOrder(); setTimeout(() => { self.clearMessage(); }, 4000); @@ -429,7 +429,7 @@ $billingAddress = $block->getQuoteBillingAddress(); } renderMethodUnavailableMessage() { - self.renderMessage('We are sorry, this method is temporarily unavailable'); + this.renderMessage('We are sorry, this method is temporarily unavailable'); } renderMessage(message) {