diff --git a/CHANGELOG.md b/CHANGELOG.md index 422b08c..e6a0a1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [4.0.2](https://github.com/unzerdev/magento2/compare/4.0.1..4.0.2) +### Fixed +* Storing PayPal and SEPA Direct Debit on Magento 2.4.8 +* Incorrect Invoice B2B UI component +### Changed +* Unblock Apple Pay on non-Safari browsers +* Reorder the default payment method list on checkout +* Set the Wero booking method mode to Charge +* Improve Unzer customer initialization using unique customerId + ## [4.0.1](https://github.com/unzerdev/magento2/compare/4.0.0..4.0.1) ### Changed * Invoice B2B component on checkout page diff --git a/Helper/Order.php b/Helper/Order.php index 7fae7a4..9353bfe 100644 --- a/Helper/Order.php +++ b/Helper/Order.php @@ -346,9 +346,9 @@ public function createCustomerFromQuote(Quote $quote, string $email, bool $creat $customer->setPhone($billingAddress->getTelephone()); $customer->setBirthDate($quote->getCustomer()->getDob()); - $customerId = (string) $quote->getCustomerId(); + $customerId = $quote->getCustomerId() . '_' . $email . '_' . $quote->getStore()->getId(); - if(!$quote->getCustomerIsGuest()) { + if (!$quote->getCustomerIsGuest()) { $customer->setCustomerId($customerId); } @@ -431,9 +431,9 @@ public function createCustomerFromOrder( } $customer->setEmail($email); - $customerId = (string) $order->getCustomerId(); + $customerId = $order->getCustomerId() . '_' . $email . '_' . $order->getStore()->getId(); - if(!$order->getCustomerIsGuest()) { + if (!$order->getCustomerIsGuest()) { $customer->setCustomerId($customerId); } diff --git a/Model/Config/Provider.php b/Model/Config/Provider.php index 3edd2ce..0167ff7 100644 --- a/Model/Config/Provider.php +++ b/Model/Config/Provider.php @@ -3,13 +3,16 @@ namespace Unzer\PAPI\Model\Config; +use Magento\Checkout\Model\Session; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Quote\Model\Quote; use Magento\Vault\Model\VaultPaymentInterface; use Unzer\PAPI\Model\Config; use Unzer\PAPI\Model\Method\Base as MethodBase; use Magento\Checkout\Model\ConfigProviderInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Payment\Helper\Data as PaymentHelper; +use UnzerSDK\Resources\Customer; /** * JavaScript configuration provider @@ -22,26 +25,26 @@ class Provider implements ConfigProviderInterface * @var array */ protected array $_methodCodes = [ - Config::METHOD_CARDS, - Config::METHOD_DIRECT_DEBIT, - Config::METHOD_EPS, - Config::METHOD_IDEAL, Config::METHOD_PAYLATER_INVOICE, Config::METHOD_PAYLATER_INVOICE_B2B, Config::METHOD_PAYLATER_INSTALLMENT, Config::METHOD_PAYLATER_DIRECT_DEBIT, - Config::METHOD_PAYPAL, - Config::METHOD_ALIPAY, - Config::METHOD_WECHATPAY, - Config::METHOD_PRZELEWY24, - Config::METHOD_BANCONTACT, - Config::METHOD_PREPAYMENT, + Config::METHOD_OPEN_BANKING, + Config::METHOD_CARDS, Config::METHOD_APPLEPAYV2, Config::METHOD_GOOGLEPAY, - Config::METHOD_TWINT, - Config::METHOD_OPEN_BANKING, - Config::METHOD_KLARNA, Config::METHOD_WERO, + Config::METHOD_KLARNA, + Config::METHOD_EPS, + Config::METHOD_IDEAL, + Config::METHOD_PRZELEWY24, + Config::METHOD_TWINT, + Config::METHOD_DIRECT_DEBIT, + Config::METHOD_PREPAYMENT, + Config::METHOD_BANCONTACT, + Config::METHOD_PAYPAL, + Config::METHOD_ALIPAY, + Config::METHOD_WECHATPAY, ]; /** @@ -59,20 +62,29 @@ class Provider implements ConfigProviderInterface */ private ScopeConfigInterface $scopeConfig; + /** + * @var Session + */ + private Session $checkoutSession; + + /** * Provider constructor. * @param Config $moduleConfig * @param PaymentHelper $paymentHelper * @param ScopeConfigInterface $scopeConfig + * @param Session $checkoutSession */ public function __construct( Config $moduleConfig, PaymentHelper $paymentHelper, - ScopeConfigInterface $scopeConfig + ScopeConfigInterface $scopeConfig, + Session $checkoutSession ) { $this->_moduleConfig = $moduleConfig; $this->_paymentHelper = $paymentHelper; $this->scopeConfig = $scopeConfig; + $this->checkoutSession = $checkoutSession; } /** @@ -83,6 +95,12 @@ public function __construct( */ public function getConfig(): array { + /** @var Quote $quote */ + $quote = $this->checkoutSession->getQuote(); + + /** @var Customer $baseCustomer */ + $baseCustomer = $quote ? $this->fetchUnzerCustomer($quote) : null; + $methodConfigs = [ Config::METHOD_BASE => [ 'publicKey' => $this->_moduleConfig->getPublicKey(), @@ -93,17 +111,58 @@ public function getConfig(): array foreach ($this->_methodCodes as $methodCode) { /** @var MethodBase $model */ $model = $this->_paymentHelper->getMethodInstance($methodCode); - if ($model instanceof VaultPaymentInterface) { + if ($model instanceof VaultPaymentInterface || !$model->isAvailable()) { continue; } - if ($model->isAvailable()) { - $methodConfigs[$model->getCode()] = $model->getFrontendConfig(); + $methodConfig = $model->getFrontendConfig(); + + if (!$model->hasMethodValidOverrideKeys()) { + if ($baseCustomer) { + $methodConfig['unzerCustomerId'] = $baseCustomer->getId(); + } + + $methodConfigs[$model->getCode()] = $methodConfig; + continue; + } + + $overrideCustomer = $this->fetchUnzerCustomer($quote, $model); + + if ($overrideCustomer) { + $methodConfig['unzerCustomerId'] = $overrideCustomer->getId(); } + + $methodConfigs[$model->getCode()] = $methodConfig; } return [ 'payment' => array_filter($methodConfigs), ]; } + + /** + * @param Quote $quote + * @param MethodBase|null $method + * + * @return Customer|null + */ + private function fetchUnzerCustomer(Quote $quote, ?MethodBase $method = null): ?Customer + { + if ($quote->getCustomerIsGuest() || !$quote->getCustomerId()) { + return null; + } + + try { + $client = $this->_moduleConfig->getUnzerClient( + $quote->getStore()->getCode(), + $method + ); + + $customerId = $quote->getCustomerId() . '_' . $quote->getCustomerEmail() . '_' . $quote->getStore()->getId(); + + return $client->fetchCustomerByExtCustomerId($customerId); + } catch (\Exception $e) { + return null; + } + } } diff --git a/Model/Method/ApplepayV2.php b/Model/Method/ApplepayV2.php index 4dacc70..90fe48c 100644 --- a/Model/Method/ApplepayV2.php +++ b/Model/Method/ApplepayV2.php @@ -21,7 +21,7 @@ public function getFrontendConfig(): array return [ 'supportedNetworks' => $supportedNetworks, 'merchantCapabilities' => ['supports3DS'], - 'label' => $this->_scopeConfig->getValue('payment/unzer_applepayv2/display_name') //label + 'label' => 'Unzer GmbH' ]; } } diff --git a/Model/Method/Invoice.php b/Model/Method/Invoice.php deleted file mode 100644 index b92c496..0000000 --- a/Model/Method/Invoice.php +++ /dev/null @@ -1,113 +0,0 @@ -_priceCurrency = $priceCurrency; - } - - /** - * Calculate Remaining Amount - * - * @param Payment $payment - * @return float - * @throws UnzerApiException - */ - protected function calculateRemainingAmount(Payment $payment): float - { - $charges = $payment->getCharges(); - $initialTransaction = $payment->getInitialTransaction(); - - if ($initialTransaction instanceof Authorization && count($charges) === 0) { - return $initialTransaction->getAmount(); - } - - $chargedAmount = 0; - foreach ($charges as $charge) { - /** @var Charge $charge */ - if ($charge->isSuccess()) { - $chargedAmount += (float)$charge->getAmount(); - } - } - - return $payment->getAmount()->getTotal() - $charges[0]->getCancelledAmount() - $chargedAmount; - } -} diff --git a/Model/Method/PaylaterInvoice.php b/Model/Method/PaylaterInvoice.php index 52097ed..8fe93c2 100644 --- a/Model/Method/PaylaterInvoice.php +++ b/Model/Method/PaylaterInvoice.php @@ -7,7 +7,7 @@ * * @link https://docs.unzer.com/ */ -class PaylaterInvoice extends Invoice implements OverrideApiCredentialInterface +class PaylaterInvoice extends Base implements OverrideApiCredentialInterface { /** * @inheritDoc diff --git a/Model/Method/PaylaterInvoiceB2b.php b/Model/Method/PaylaterInvoiceB2b.php index 6355a62..2b752d0 100644 --- a/Model/Method/PaylaterInvoiceB2b.php +++ b/Model/Method/PaylaterInvoiceB2b.php @@ -7,7 +7,7 @@ * * @link https://docs.unzer.com/ */ -class PaylaterInvoiceB2b extends Invoice implements OverrideApiCredentialInterface +class PaylaterInvoiceB2b extends Base implements OverrideApiCredentialInterface { /** * @inheritDoc diff --git a/Model/Vault/Handlers/DirectDebitVaultDetailsHandler.php b/Model/Vault/Handlers/DirectDebitVaultDetailsHandler.php index ceb54fa..4ea7de7 100644 --- a/Model/Vault/Handlers/DirectDebitVaultDetailsHandler.php +++ b/Model/Vault/Handlers/DirectDebitVaultDetailsHandler.php @@ -28,24 +28,58 @@ */ class DirectDebitVaultDetailsHandler implements VaultDetailsHandlerInterface { + /** + * @var PaymentTokenFactoryInterface + */ private PaymentTokenFactoryInterface $paymentTokenFactory; + + /** + * @var OrderPaymentExtensionInterfaceFactory + */ private OrderPaymentExtensionInterfaceFactory $paymentExtensionFactory; + + /** + * @var Json + */ private Json $serializer; + + /** + * @var DateTimeFactory + */ private DateTimeFactory $dateTimeFactory; + + /** + * @var PaymentTokenResourceModel + */ private PaymentTokenResourceModel $paymentTokenResourceModel; + /** + * @var VaultTokenPersister + */ + private VaultTokenPersister $vaultTokenPersister; + + /** + * @param PaymentTokenFactoryInterface $paymentTokenFactory + * @param OrderPaymentExtensionInterfaceFactory $paymentExtensionFactory + * @param Json $serializer + * @param DateTimeFactory $dateTimeFactory + * @param PaymentTokenResourceModel $paymentTokenResourceModel + * @param VaultTokenPersister $vaultTokenPersister + */ public function __construct( PaymentTokenFactoryInterface $paymentTokenFactory, OrderPaymentExtensionInterfaceFactory $paymentExtensionFactory, Json $serializer, DateTimeFactory $dateTimeFactory, - PaymentTokenResourceModel $paymentTokenResourceModel + PaymentTokenResourceModel $paymentTokenResourceModel, + VaultTokenPersister $vaultTokenPersister ) { $this->paymentTokenFactory = $paymentTokenFactory; $this->paymentExtensionFactory = $paymentExtensionFactory; $this->serializer = $serializer; $this->dateTimeFactory = $dateTimeFactory; $this->paymentTokenResourceModel = $paymentTokenResourceModel; + $this->vaultTokenPersister = $vaultTokenPersister; } /** @@ -77,7 +111,11 @@ public function handle(PaymentDataObject $payment, AbstractTransactionType $tran $paymentToken = $this->createVaultPaymentToken($transaction, $payment); if ($paymentToken !== null) { - $extensionAttributes = $this->getExtensionAttributes($payment->getPayment()); + $orderPayment = $payment->getPayment(); + + $this->vaultTokenPersister->save($paymentToken, $orderPayment); + + $extensionAttributes = $this->getExtensionAttributes($orderPayment); $extensionAttributes->setVaultPaymentToken($paymentToken); } } diff --git a/Model/Vault/Handlers/PaypalVaultDetailsHandler.php b/Model/Vault/Handlers/PaypalVaultDetailsHandler.php index 7143c0b..5dc3bf5 100644 --- a/Model/Vault/Handlers/PaypalVaultDetailsHandler.php +++ b/Model/Vault/Handlers/PaypalVaultDetailsHandler.php @@ -53,6 +53,11 @@ class PaypalVaultDetailsHandler implements VaultDetailsHandlerInterface */ private PaymentTokenResourceModel $paymentTokenResourceModel; + /** + * @var VaultTokenPersister + */ + private VaultTokenPersister $vaultTokenPersister; + /** * Constructor * @@ -61,19 +66,22 @@ class PaypalVaultDetailsHandler implements VaultDetailsHandlerInterface * @param DateTimeFactory $dateTimeFactory * @param Json $serializer * @param PaymentTokenResourceModel $paymentTokenResourceModel + * @param VaultTokenPersister $vaultTokenPersister */ public function __construct( PaymentTokenFactoryInterface $paymentTokenFactory, OrderPaymentExtensionInterfaceFactory $paymentExtensionFactory, DateTimeFactory $dateTimeFactory, Json $serializer, - PaymentTokenResourceModel $paymentTokenResourceModel + PaymentTokenResourceModel $paymentTokenResourceModel, + VaultTokenPersister $vaultTokenPersister ) { $this->paymentTokenFactory = $paymentTokenFactory; $this->paymentExtensionFactory = $paymentExtensionFactory; $this->serializer = $serializer; $this->dateTimeFactory = $dateTimeFactory; $this->paymentTokenResourceModel = $paymentTokenResourceModel; + $this->vaultTokenPersister = $vaultTokenPersister; } /** @@ -106,7 +114,11 @@ public function handle(PaymentDataObject $payment, AbstractTransactionType $tran // add vault payment token entity to extension attributes $paymentToken = $this->createVaultPaymentToken($transaction, $payment); if (null !== $paymentToken) { - $extensionAttributes = $this->getExtensionAttributes($payment->getPayment()); + $orderPayment = $payment->getPayment(); + + $this->vaultTokenPersister->save($paymentToken, $orderPayment); + + $extensionAttributes = $this->getExtensionAttributes($orderPayment); $extensionAttributes->setVaultPaymentToken($paymentToken); } } diff --git a/Model/Vault/Handlers/VaultTokenPersister.php b/Model/Vault/Handlers/VaultTokenPersister.php new file mode 100644 index 0000000..8315d81 --- /dev/null +++ b/Model/Vault/Handlers/VaultTokenPersister.php @@ -0,0 +1,98 @@ +paymentTokenManagement = $paymentTokenManagement; + $this->encryptor = $encryptor; + } + + /** + * @param PaymentTokenInterface $paymentToken + * @param OrderPaymentInterface $payment + * + * @return void + */ + public function save(PaymentTokenInterface $paymentToken, OrderPaymentInterface $payment): void + { + if (!$paymentToken->getGatewayToken()) { + return; + } + + $order = $payment->getOrder(); + if (!$order) { + return; + } + + if ($paymentToken->getEntityId()) { + $this->paymentTokenManagement->addLinkToOrderPayment( + $paymentToken->getEntityId(), + $payment->getEntityId() + ); + + return; + } + + $paymentToken->setCustomerId($order->getCustomerId()); + $paymentToken->setIsActive(true); + $paymentToken->setPaymentMethodCode($payment->getMethod()); + + $additionalInformation = $payment->getAdditionalInformation(); + $paymentToken->setIsVisible( + (bool)(int)($additionalInformation[VaultConfigProvider::IS_ACTIVE_CODE] ?? 0) + ); + + $paymentToken->setPublicHash( + $this->generatePublicHash($paymentToken, (int)$order->getCustomerId()) + ); + + $this->paymentTokenManagement->saveTokenWithPaymentLink($paymentToken, $payment); + } + + /** + * @param PaymentTokenInterface $paymentToken + * @param int|null $customerId + * + * @return string + */ + private function generatePublicHash(PaymentTokenInterface $paymentToken, ?int $customerId): string + { + return $this->encryptor->getHash( + ($customerId ?: '') + . $paymentToken->getPaymentMethodCode() + . $paymentToken->getType() + . $paymentToken->getTokenDetails() + ); + } +} diff --git a/Setup/Patch/Data/UpdateWeroOrderPaymentAction.php b/Setup/Patch/Data/UpdateWeroOrderPaymentAction.php new file mode 100644 index 0000000..038ce4c --- /dev/null +++ b/Setup/Patch/Data/UpdateWeroOrderPaymentAction.php @@ -0,0 +1,57 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * @return $this|UpdateWeroOrderPaymentAction + */ + public function apply(): UpdateWeroOrderPaymentAction + { + $connection = $this->moduleDataSetup->getConnection(); + + $connection->update( + $this->moduleDataSetup->getTable('core_config_data'), + ['value' => 'authorize_capture'], + ['path = ?' => self::CONFIG_PATH] + ); + + return $this; + } + + /** + * @return array|string[] + */ + public static function getDependencies(): array + { + return []; + } + + /** + * @return array|string[] + */ + public function getAliases(): array + { + return []; + } +} diff --git a/composer.json b/composer.json index 7ec6365..294f122 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "unzerdev/magento2", "description": "This extension for Magento 2 provides a direct integration of the Unzer payment types to your Magento 2 shop via the Unzer Payment API (PAPI).", "type": "magento2-module", - "version": "4.0.1", + "version": "4.0.2", "license": "Apache-2.0", "require": { "php": "~7.4.0|~8.1.0|~8.2.0|~8.3.0|~8.4.0", diff --git a/etc/adminhtml/system/wero.xml b/etc/adminhtml/system/wero.xml index 278ebb0..91e3ea8 100644 --- a/etc/adminhtml/system/wero.xml +++ b/etc/adminhtml/system/wero.xml @@ -11,12 +11,6 @@ Title payment/unzer_wero/title - - Booking Mode - payment/unzer_wero/order_payment_action - Unzer\PAPI\Model\System\Config\Source\PaymentAction - Minimum Order Total payment/unzer_wero/min_order_total diff --git a/etc/config.xml b/etc/config.xml index 03240f7..1b4e84b 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -9,83 +9,6 @@ Unzer\PAPI\Model\Method\Base 0 - - 0 - order - authorize - - 0 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 0 - 0 - Unzer\PAPI\Model\Method\Cards - - - 0 - 0 - - Unzer\PAPI\Model\InstantPurchase\CreditCard\AvailabilityChecker - Unzer\PAPI\Model\InstantPurchase\CreditCard\TokenFormatter - - UnzerCardsVault - - - - 0 - authorize_capture - authorize_capture - - 0 - 0 - 0 - 0 - 0 - 1 - 1 - 0 - 1 - 0 - 1 - EUR - Unzer\PAPI\Model\Method\DirectDebit - - - 0 - 0 - - Unzer\PAPI\Model\InstantPurchase\DirectDebit\AvailabilityChecker - Unzer\PAPI\Model\InstantPurchase\DirectDebit\TokenFormatter - - UnzerDirectDebitVault - - EUR - - - 0 - order - authorize_capture - - 0 - 0 - 0 - NL - EUR - 0 - 1 - 1 - 1 - 0 - Unzer\PAPI\Model\Method\Ideal - 0 order @@ -166,11 +89,29 @@ processing Unzer\PAPI\Model\Method\PaylaterDirectDebit - + + 0 + order + authorize_capture + + 0 + 0 + 0 + DE + EUR + 0 + 1 + 1 + 1 + 1 + 0 + Unzer\PAPI\Model\Method\OpenBanking + + 0 order authorize - + 0 0 0 @@ -183,92 +124,99 @@ 1 1 0 - 1 - Unzer\PAPI\Model\Method\Paypal - - + 0 + Unzer\PAPI\Model\Method\Cards + + 0 0 - Unzer\PAPI\Model\InstantPurchase\PayPal\AvailabilityChecker - Unzer\PAPI\Model\InstantPurchase\PayPal\TokenFormatter + Unzer\PAPI\Model\InstantPurchase\CreditCard\AvailabilityChecker + Unzer\PAPI\Model\InstantPurchase\CreditCard\TokenFormatter - UnzerPaypalVault - - - + UnzerCardsVault + + + 0 order authorize_capture - + 0 0 0 - 0 + 1 1 1 + 1 1 0 - AT - EUR - Unzer\PAPI\Model\Method\EPS - - + Unzer\PAPI\Model\Method\ApplepayV2 + + 0 order authorize_capture - + 0 0 0 - 0 + 1 1 + 1 1 + 1 1 0 - DE,AT,BE,IT,ES,NL - AUD,CAD,CHF,CNY,EUR,GBP,HKD,NZD,SGD,USD - Unzer\PAPI\Model\Method\Alipay - - + Unzer\PAPI\Model\Method\Googlepay + 12345678901234567890 + Example Merchant + DK + default + fill + 2 + + 0 order - authorize_capture - + authorize + 0 0 0 - 0 + EUR + DE + 1 1 + 1 1 + 1 1 0 - AT,BE,DK,FI,FR,DE,ES,GB,GR,HU,IE,IS,IT,LI,LU,MT,NL,NO,PT,SE - CHF,CNY,EUR,GBP,USD - Unzer\PAPI\Model\Method\Wechatpay - - + Unzer\PAPI\Model\Method\Wero + + 0 order - authorize_capture - + authorize + 0 0 0 - 0 + 1 1 + 1 1 + 1 1 0 - PL - PLN,EUR - Unzer\PAPI\Model\Method\Przelewy24 - - + Unzer\PAPI\Model\Method\Klarna + + 0 order authorize_capture - + 0 0 0 @@ -277,138 +225,190 @@ 1 1 0 - BE + AT EUR - Unzer\PAPI\Model\Method\Bancontact - - + Unzer\PAPI\Model\Method\EPS + + 0 order authorize_capture - + 0 0 0 + NL + EUR 0 1 1 - 1 1 0 - 1 - EUR - Unzer\PAPI\Model\Method\Prepayment - - + Unzer\PAPI\Model\Method\Ideal + + 0 order authorize_capture - + 0 0 0 - 1 + 0 1 1 - 1 1 0 - Unzer\PAPI\Model\Method\ApplepayV2 - - + PL + PLN,EUR + Unzer\PAPI\Model\Method\Przelewy24 + + 0 order authorize_capture - + 0 0 0 - 1 + 0 1 - 1 1 - 1 1 0 - Unzer\PAPI\Model\Method\Googlepay - 12345678901234567890 - Example Merchant - DK - default - fill - 2 - - + CH + CHF + Unzer\PAPI\Model\Method\Twint + + + 0 + authorize_capture + authorize_capture + + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 1 + 0 + 1 + EUR + Unzer\PAPI\Model\Method\DirectDebit + + + 0 + 0 + + Unzer\PAPI\Model\InstantPurchase\DirectDebit\AvailabilityChecker + Unzer\PAPI\Model\InstantPurchase\DirectDebit\TokenFormatter + + UnzerDirectDebitVault + + EUR + + 0 order authorize_capture - + 0 0 0 0 1 1 + 1 1 0 - CH - CHF - Unzer\PAPI\Model\Method\Twint - - + 1 + EUR + Unzer\PAPI\Model\Method\Prepayment + + 0 order authorize_capture - + 0 0 0 - DE - EUR 0 1 1 - 1 1 0 - Unzer\PAPI\Model\Method\OpenBanking - - + BE + EUR + Unzer\PAPI\Model\Method\Bancontact + + 0 order authorize - + 0 0 0 1 + 1 + 1 1 1 1 1 1 0 - Unzer\PAPI\Model\Method\Klarna - - + 1 + Unzer\PAPI\Model\Method\Paypal + + + 0 + 0 + + Unzer\PAPI\Model\InstantPurchase\PayPal\AvailabilityChecker + Unzer\PAPI\Model\InstantPurchase\PayPal\TokenFormatter + + UnzerPaypalVault + + + 0 order - authorize - + authorize_capture + 0 0 0 - EUR - DE - 1 + 0 1 - 1 1 - 1 1 0 - Unzer\PAPI\Model\Method\Wero - + DE,AT,BE,IT,ES,NL + AUD,CAD,CHF,CNY,EUR,GBP,HKD,NZD,SGD,USD + Unzer\PAPI\Model\Method\Alipay + + + 0 + order + authorize_capture + + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + AT,BE,DK,FI,FR,DE,ES,GB,GR,HU,IE,IS,IT,LI,LU,MT,NL,NO,PT,SE + CHF,CNY,EUR,GBP,USD + Unzer\PAPI\Model\Method\Wechatpay + diff --git a/etc/module.xml b/etc/module.xml index 32eb361..f8e2cb8 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,7 +1,7 @@ - + diff --git a/view/frontend/templates/customer_account/credit_card.phtml b/view/frontend/templates/customer_account/credit_card.phtml index b2d486d..d7c0daf 100644 --- a/view/frontend/templates/customer_account/credit_card.phtml +++ b/view/frontend/templates/customer_account/credit_card.phtml @@ -9,38 +9,42 @@ use Magento\Vault\Block\CardRendererInterface; $ccNumberView = $block->escapeHtml($block->getNumberLast4Digits()); ?> - - - = /* @noEscape */ $ccNumberView ?> + + + = /* @noEscape */ + $ccNumberView ?> - + + = $block->escapeHtml($block->getExpDate()) ?> - + + = $block->escapeHtml($block->getBrand()) ?> - - + + + = $block->getBlockHtml('formkey') ?> - + + + ", - "content": "= $block->escapeHtml(__('Are you sure you want to delete this card: %1?', $ccNumberView)) ?>" - } - }'> + "Magento_Vault/js/customer_account/deleteWidget": { + "type": "popup", + "modalClass": "my-credit-cards-popup", + "toggleEvent": "click", + "title": "= $block->escapeHtml(__('Delete')) ?>", + "content": "= $block->escapeHtml(__('Are you sure you want to delete this card: %1?', + $ccNumberView)) ?>" + } + }'> = $block->escapeHtml(__('Delete')) ?> diff --git a/view/frontend/templates/customer_account/direct_debit.phtml b/view/frontend/templates/customer_account/direct_debit.phtml index 402c5a7..d5a846e 100644 --- a/view/frontend/templates/customer_account/direct_debit.phtml +++ b/view/frontend/templates/customer_account/direct_debit.phtml @@ -2,37 +2,37 @@ declare(strict_types=1); use Magento\Framework\View\Element\Template; -use Unzer\PAPI\Block\Customer\DirectDebitRenderer; use Magento\Vault\Api\Data\PaymentTokenInterface; +use Unzer\PAPI\Block\Customer\DirectDebitRenderer; /** @var Template|DirectDebitRenderer $block */ -$maskedIban = (string)$block->escapeHtml($block->getMaskedIban()); -$holder = (string)$block->escapeHtml($block->getAccountHolder()); -?> - - - = /* @noEscape */ - $maskedIban ?> +$maskedIban = $block->escapeHtml($block->getMaskedIban()); +$holder = $block->escapeHtml($block->getAccountHolder()); +?> + + + = $maskedIban ?> - - = /* @noEscape */ - $holder ?> + + + = $holder ?> - + + = $block->escapeHtml(__('SEPA Direct Debit')) ?> - + + = $block->getBlockHtml('formkey') ?> - + + + ", - "content": "= $block->escapeHtmlAttr(__('Are you sure you want to delete this SEPA mandate: %1 (%2)?', - $maskedIban, $holder)) ?>" + "content": "= $block->escapeHtmlAttr( + __('Are you sure you want to delete this SEPA mandate: %1 (%2)?', $maskedIban, $holder) + ) ?>" } }'> = $block->escapeHtml(__('Delete')) ?> diff --git a/view/frontend/templates/customer_account/paypal.phtml b/view/frontend/templates/customer_account/paypal.phtml index d5c989b..1f78fae 100644 --- a/view/frontend/templates/customer_account/paypal.phtml +++ b/view/frontend/templates/customer_account/paypal.phtml @@ -9,30 +9,29 @@ use Unzer\PAPI\Block\Customer\PaypalRenderer; $payerEmail = (string)$block->escapeHtml($block->getPayerEmail()); ?> - - - = /* @noEscape */ - $payerEmail ?> + + + = $payerEmail ?> - + + + - + = $block->escapeHtml(__('PayPal')) ?> - + = $block->getBlockHtml('formkey') ?> - + + + ", - "content": "= $block->escapeHtmlAttr(__('Are you sure you want to delete this PayPal account: %1?', - $payerEmail)) ?>" + "content": "= $block->escapeHtmlAttr( + __('Are you sure you want to delete this PayPal account: %1?', $payerEmail) + ) ?>" } }'> = $block->escapeHtml(__('Delete')) ?> diff --git a/view/frontend/templates/token_list.phtml b/view/frontend/templates/token_list.phtml index e9aaa18..cdfd739 100644 --- a/view/frontend/templates/token_list.phtml +++ b/view/frontend/templates/token_list.phtml @@ -7,38 +7,54 @@ if (empty($tokens)) { $groups = [ 'paypal' => [], - 'direct_debit' => [], + 'direct_debit' => [], ]; foreach ($tokens as $token) { - $code = $token->getPaymentMethodCode(); + $code = (string)$token->getPaymentMethodCode(); - if (strpos($code, 'paypal')) { + if (strpos($code, 'paypal') !== false) { $groups['paypal'][] = $token; } - if (strpos($code, 'direct_debit')) { + if (strpos($code, 'direct_debit') !== false) { $groups['direct_debit'][] = $token; } } $titles = [ 'paypal' => __('PayPal Account'), - 'direct_debit' => __('SEPA Direct Debit'), + 'direct_debit' => __('SEPA Direct Debit'), ]; ?> + + + + + + + + + + + - = $block->escapeHtml($titles[$groupKey]) ?> + + = $block->escapeHtml($titles[$groupKey]) ?> + + - = /* @noEscape */ $block->renderTokenHtml($token) ?> + = /* @noEscape */ + $block->renderTokenHtml($token) ?> + diff --git a/view/frontend/web/css/source/_extend.less b/view/frontend/web/css/source/_extend.less index 09513f1..e47884e 100644 --- a/view/frontend/web/css/source/_extend.less +++ b/view/frontend/web/css/source/_extend.less @@ -22,4 +22,21 @@ border: 0; } } + + .table-wrapper.my-credit-cards table { + width: 100%; + border-collapse: collapse; + } + + .table-wrapper.my-credit-cards th.card-number, + .table-wrapper.my-credit-cards td.card-number { width: 30%; } + + .table-wrapper.my-credit-cards th.card-expire, + .table-wrapper.my-credit-cards td.card-expire { width: 30%; } + + .table-wrapper.my-credit-cards th.card-type, + .table-wrapper.my-credit-cards td.card-type { width: 20%; } + + .table-wrapper.my-credit-cards th.actions, + .table-wrapper.my-credit-cards td.actions { width: 20%; } } diff --git a/view/frontend/web/js/view/payment/method-renderer/applepayv2.js b/view/frontend/web/js/view/payment/method-renderer/applepayv2.js index 9d300cd..950f6d0 100644 --- a/view/frontend/web/js/view/payment/method-renderer/applepayv2.js +++ b/view/frontend/web/js/view/payment/method-renderer/applepayv2.js @@ -25,17 +25,11 @@ define( paymentCode: 'unzer-apple-pay' }, - isApplePayAvailable: function () { - return window.ApplePaySession && ApplePaySession.canMakePayments(); - }, - selectPaymentMethod: function () { let retVal = this._super(); const componentContainer = $('#unzer-component-' + this.getCode()); - if(this.isApplePayAvailable()){ - componentContainer.addClass('apple-pay-button'); - } + componentContainer.addClass('apple-pay-button'); this.waitForSetApplePayData(); const unzerCheckoutElementId = 'unzer-checkout-' + this.getCode(); @@ -61,14 +55,12 @@ define( if (unzerPaymentElement && typeof unzerPaymentElement.setApplePayData === 'function') { const supportedNetworks = window.checkoutConfig.payment.unzer_applepayv2.supportedNetworks.map((network) => network.toLowerCase()); - + const billing = quote.billingAddress && quote.billingAddress(); const totals = quote.totals() ? quote.totals() : window.checkoutConfig.quoteData; unzerPaymentElement.setApplePayData({ - countryCode: quote.billingAddress().countryId, + countryCode: billing?.countryId, currencyCode: window.checkoutConfig.quoteData.base_currency_code, - totalLabel: window.checkoutConfig.payment.unzer_applepayv2.label, - totalAmount: Number(totals['base_grand_total']).toFixed(2), supportedNetworks: supportedNetworks, merchantCapabilities: window.checkoutConfig.payment.unzer_applepayv2.merchantCapabilities, requiredShippingContactFields: [], diff --git a/view/frontend/web/js/view/payment/method-renderer/basev2.js b/view/frontend/web/js/view/payment/method-renderer/basev2.js index d14a2db..3193d90 100644 --- a/view/frontend/web/js/view/payment/method-renderer/basev2.js +++ b/view/frontend/web/js/view/payment/method-renderer/basev2.js @@ -247,50 +247,69 @@ define( const unzerCheckoutElementId = 'unzer-payment-' + this.getCode(); const unzerPayment = document.getElementById(unzerCheckoutElementId); - if (unzerPayment && typeof unzerPayment.setBasketData === 'function') { - unzerPayment.setBasketData({ - amount: (quote.totals() ? quote.totals() : quote)['base_grand_total'], - currencyType: (quote.totals() ? quote.totals() : quote)['base_currency_code'] - }) + if (!unzerPayment || typeof unzerPayment.setBasketData !== 'function') { + if (maxRetries > 0) { + setTimeout(() => this.waitForSetBasketData(maxRetries - 1, interval), interval); + } else { + console.error('setBasketData is not available after multiple retries.'); + } + return; + } - const billing = quote.billingAddress(); - const shipping = quote.shippingAddress(); - - const customer = { - firstname: billing ? billing.firstname : '', - lastname: billing ? billing.lastname : '', - email: quote.guestEmail ? quote.guestEmail : (window.customerData ? window.customerData.email : ''), - ...(customerData?.dob ? { birthDate: customerData.dob.split('T')[0] } : {}), - billingAddress: billing ? { - name: (billing.firstname || '') + ' ' + (billing.lastname || ''), - street: Array.isArray(billing.street) ? billing.street.join(' ') : billing.street, - zip: billing.postcode, - city: billing.city, - country: billing.countryId - } : {}, - - shippingAddress: shipping ? { - name: (shipping.firstname || '') + ' ' + (shipping.lastname || ''), - street: Array.isArray(shipping.street) ? shipping.street.join(' ') : shipping.street, - zip: shipping.postcode, - city: shipping.city, - country: shipping.countryId - } : {}, - ...(billing?.company && billing.company.trim() !== '' - ? { company: billing.company.trim() } - : {}), - customerSettings: { - type: billing?.company && billing.company.trim() !== '' ? 'B2B' : 'B2C' - } - }; + unzerPayment.setBasketData({ + amount: (quote.totals() ? quote.totals() : quote)['base_grand_total'], + currencyType: (quote.totals() ? quote.totals() : quote)['base_currency_code'] + }) + + const methodConfig = window.checkoutConfig.payment[this.getCode()] || {}; + const unzerCustomerId = methodConfig.unzerCustomerId || null; + + const email = quote.guestEmail + ? quote.guestEmail + : (window.customerData ? window.customerData.email : ''); - unzerPayment.setCustomerData(customer); - } else if (maxRetries > 0) { - console.log('Waiting for setBasketData function to be available...'); - setTimeout(() => this.waitForSetBasketData(maxRetries - 1, interval), interval); - } else { - console.error('setBasketData is not available after multiple retries.'); + const shop = window.checkoutConfig?.quoteData.store_id || ''; + + const billing = quote.billingAddress(); + const shipping = quote.shippingAddress(); + + const customerId = window.checkoutConfig?.customerData.id || ''; + const uniqueCustomerId = `${customerId}_${email}_${shop}`; + + if (unzerCustomerId) { + this.customer = unzerCustomerId; } + + const customer = { + id: unzerCustomerId || '', + customerId: uniqueCustomerId, + firstname: billing ? billing.firstname : '', + lastname: billing ? billing.lastname : '', + email: email, + ...(customerData?.dob ? {birthDate: customerData.dob.split('T')[0]} : {}), + billingAddress: billing ? { + name: (billing.firstname || '') + ' ' + (billing.lastname || ''), + street: Array.isArray(billing.street) ? billing.street.join(' ') : billing.street, + zip: billing.postcode, + city: billing.city, + country: billing.countryId + } : {}, + + shippingAddress: shipping ? { + name: (shipping.firstname || '') + ' ' + (shipping.lastname || ''), + street: Array.isArray(shipping.street) ? shipping.street.join(' ') : shipping.street, + zip: shipping.postcode, + city: shipping.city, + country: shipping.countryId + } : {}, + ...(billing?.company && billing.company.trim() !== '' + ? {company: billing.company.trim()} + : {}), + customerSettings: { + type: billing?.company && billing.company.trim() !== '' ? 'B2B' : 'B2C' + } + }; + unzerPayment.setCustomerData(customer); }, getPlaceOrderDeferredObject: function () { @@ -305,7 +324,7 @@ define( unzerCheckout.onPaymentSubmit = response => { if (response.submitResponse && response.submitResponse.success) { - if(response.customerResponse && response.customerResponse.success) { + if (response.customerResponse && response.customerResponse.success) { this.customer = response.customerResponse.data.id; } this.resourceId = response.submitResponse.data.id; diff --git a/view/frontend/web/template/payment/applepayv2.html b/view/frontend/web/template/payment/applepayv2.html index 9285e70..5112345 100644 --- a/view/frontend/web/template/payment/applepayv2.html +++ b/view/frontend/web/template/payment/applepayv2.html @@ -10,7 +10,7 @@ - +