From 304b935a8281b72d182a5e8f65c86adbb8fab3e5 Mon Sep 17 00:00:00 2001 From: Aidan Threadgold Date: Tue, 11 Feb 2020 09:48:13 +0000 Subject: [PATCH 01/37] Wrap credit API calls in DB Transaction --- Cron/CreditPrice.php | 49 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/Cron/CreditPrice.php b/Cron/CreditPrice.php index 1adb097b..41cc86a0 100644 --- a/Cron/CreditPrice.php +++ b/Cron/CreditPrice.php @@ -2,18 +2,12 @@ namespace Magento\Braintree\Cron; -use Exception; -use Magento\Braintree\Api\CreditPriceRepositoryInterface; use Magento\Braintree\Api\Data\CreditPriceDataInterface; -use Magento\Braintree\Api\Data\CreditPriceDataInterfaceFactory; use Magento\Braintree\Gateway\Config\PayPalCredit\Config as PayPalCreditConfig; -use Magento\Braintree\Model\Paypal\CreditApi; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory; -use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\AuthenticationException; use Magento\Framework\Exception\LocalizedException; use Psr\Log\LoggerInterface; -use RuntimeException; /** * Class CreditPrice @@ -22,12 +16,12 @@ class CreditPrice { /** - * @var CreditPriceRepositoryInterface + * @var \Magento\Braintree\Api\CreditPriceRepositoryInterface */ private $creditPriceRepository; /** - * @var ScopeConfigInterface + * @var \Magento\Framework\App\Config\ScopeConfigInterface */ private $scopeConfig; @@ -37,7 +31,7 @@ class CreditPrice private $productCollection; /** - * @var CreditPriceDataInterfaceFactory + * @var \Magento\Braintree\Api\Data\CreditPriceDataInterfaceFactory */ private $creditPriceFactory; @@ -47,7 +41,7 @@ class CreditPrice private $logger; /** - * @var CreditApi + * @var \Magento\Braintree\Model\Paypal\CreditApi */ private $creditApi; @@ -58,19 +52,19 @@ class CreditPrice /** * CreditPrice constructor. - * @param CreditPriceRepositoryInterface $creditPriceRepository - * @param CreditPriceDataInterfaceFactory $creditPriceDataInterfaceFactory - * @param ScopeConfigInterface $scopeConfig - * @param CreditApi $creditApi + * @param \Magento\Braintree\Api\CreditPriceRepositoryInterface $creditPriceRepository + * @param \Magento\Braintree\Api\Data\CreditPriceDataInterfaceFactory $creditPriceDataInterfaceFactory + * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + * @param \Magento\Braintree\Model\Paypal\CreditApi $creditApi * @param ProductCollectionFactory $productCollection * @param LoggerInterface $logger * @param PayPalCreditConfig $config */ public function __construct( - CreditPriceRepositoryInterface $creditPriceRepository, - CreditPriceDataInterfaceFactory $creditPriceDataInterfaceFactory, - ScopeConfigInterface $scopeConfig, - CreditApi $creditApi, + \Magento\Braintree\Api\CreditPriceRepositoryInterface $creditPriceRepository, + \Magento\Braintree\Api\Data\CreditPriceDataInterfaceFactory $creditPriceDataInterfaceFactory, + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, + \Magento\Braintree\Model\Paypal\CreditApi $creditApi, ProductCollectionFactory $productCollection, LoggerInterface $logger, PayPalCreditConfig $config @@ -86,19 +80,23 @@ public function __construct( /** * @return $this - * @throws Exception + * @throws \Exception */ - public function execute(): self + public function execute() { if (!$this->config->isCalculatorEnabled()) { return $this; } // Retrieve paginated collection of product and their price + /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ $collection = $this->productCollection->create(); $collection->addAttributeToSelect('price') ->setPageSize(100); + $connection = $collection->getResource()->getConnection(); + $connection->beginTransaction(); + $lastPage = $collection->getLastPageNumber(); for ($i = 1; $i <= $lastPage; $i++) { $collection->setCurPage($i); @@ -113,7 +111,7 @@ public function execute(): self $priceOptions = $this->creditApi->getPriceOptions($product->getFinalPrice()); foreach ($priceOptions as $priceOption) { // Populate model - /** @var CreditPriceDataInterface $model */ + /** @var $model \Magento\Braintree\Api\Data\CreditPriceDataInterface */ $model = $this->creditPriceFactory->create(); $model->setProductId($product->getId()); $model->setTerm($priceOption['term']); @@ -124,14 +122,23 @@ public function execute(): self $this->creditPriceRepository->save($model); } + } catch (AuthenticationException $e) { + $connection->rollBack(); + throw new \Exception($e->getMessage()); } catch (LocalizedException $e) { $this->logger->critical($e->getMessage()); + } catch (\Exception $e) { + $connection->rollBack(); + $this->logger->critical($e->getMessage()); + return $this; } } $collection->clear(); } + $connection->commit(); + return $this; } } From 0e4a0b7fa069f95bb772700ff1e06ced68c341c6 Mon Sep 17 00:00:00 2001 From: Paul Canning Date: Fri, 3 Jul 2020 14:05:44 +0100 Subject: [PATCH 02/37] LPMs incorrectly showed message stating no payment methods when at least 1 was available, in certain scenarios. --- view/frontend/web/js/view/payment/method-renderer/lpm.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/lpm.js b/view/frontend/web/js/view/payment/method-renderer/lpm.js index f74516e7..0c81ef2c 100644 --- a/view/frontend/web/js/view/payment/method-renderer/lpm.js +++ b/view/frontend/web/js/view/payment/method-renderer/lpm.js @@ -232,9 +232,6 @@ define( this.paymentMethodsAvailable(true); return true; } - - this.paymentMethodsAvailable(false); - return false; }, setErrorMsg: function (message) { From b93a636a59e82ca48ee8fc443acb71f573cef252 Mon Sep 17 00:00:00 2001 From: Brandon Martus Date: Thu, 23 Jul 2020 12:52:46 -0500 Subject: [PATCH 03/37] resolve descriptors from current store --- Gateway/Config/Config.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 03ff9686..c239cad4 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -340,7 +340,10 @@ public function getDynamicDescriptors(): array { $values = []; foreach (self::$dynamicDescriptorKeys as $key) { - $value = $this->getValue('descriptor_' . $key); + $value = $this->getValue( + 'descriptor_' . $key, + $this->storeConfigResolver->getStoreId() + ); if (!empty($value)) { $values[$key] = $value; } From ee60d80b659b479357433677af9c28c4b0690560 Mon Sep 17 00:00:00 2001 From: kartik Date: Tue, 28 Jul 2020 20:14:06 +0530 Subject: [PATCH 04/37] [PBSD-9] Disabled vaulting for cards if vault is disabled --- Gateway/Request/VaultDataBuilder.php | 32 ++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Gateway/Request/VaultDataBuilder.php b/Gateway/Request/VaultDataBuilder.php index e77f2de4..0bd6e61b 100755 --- a/Gateway/Request/VaultDataBuilder.php +++ b/Gateway/Request/VaultDataBuilder.php @@ -6,6 +6,8 @@ namespace Magento\Braintree\Gateway\Request; use Magento\Payment\Gateway\Request\BuilderInterface; +use PayPal\Braintree\Gateway\Helper\SubjectReader; +use Magento\Vault\Model\Ui\VaultConfigProvider; /** * Vault Data Builder @@ -23,15 +25,37 @@ class VaultDataBuilder implements BuilderInterface */ const STORE_IN_VAULT_ON_SUCCESS = 'storeInVaultOnSuccess'; + /** + * @var SubjectReader + */ + protected $subjectReader; + + /** + * VaultDataBuilder constructor. + * + * @param SubjectReader $subjectReader + */ + public function __construct(SubjectReader $subjectReader) + { + $this->subjectReader = $subjectReader; + } + /** * @inheritdoc */ public function build(array $buildSubject): array { - return [ - self::OPTIONS => [ + $result = []; + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $payment = $paymentDO->getPayment(); + $data = $payment->getAdditionalInformation(); + + if (!empty($data[VaultConfigProvider::IS_ACTIVE_CODE])) { + $result[self::OPTIONS] = [ self::STORE_IN_VAULT_ON_SUCCESS => true - ] - ]; + ]; + } + + return $result; } } From 024836a03128a84f804dabef531bcd144741952f Mon Sep 17 00:00:00 2001 From: kartik Date: Wed, 29 Jul 2020 11:11:23 +0530 Subject: [PATCH 05/37] [PBSD-31] Fixed Shipping Method is not getting updated on PayPal Review Order and Google Pay page. --- Model/Paypal/Helper/ShippingMethodUpdater.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Model/Paypal/Helper/ShippingMethodUpdater.php b/Model/Paypal/Helper/ShippingMethodUpdater.php index 9c712d00..f4f10d2c 100755 --- a/Model/Paypal/Helper/ShippingMethodUpdater.php +++ b/Model/Paypal/Helper/ShippingMethodUpdater.php @@ -51,8 +51,14 @@ public function execute($shippingMethod, Quote $quote) $shippingAddress->setShippingMethod($shippingMethod); $shippingAddress->setCollectShippingRates(true); - $quote->collectTotals(); + $cartExtension = $quote->getExtensionAttributes(); + if ($cartExtension && $cartExtension->getShippingAssignments()) { + $cartExtension->getShippingAssignments()[0] + ->getShipping() + ->setMethod($shippingMethod); + } + $quote->collectTotals(); $this->quoteRepository->save($quote); } } From e8d247017787078910591efd252ebeed175fde07 Mon Sep 17 00:00:00 2001 From: kartik Date: Wed, 29 Jul 2020 13:01:42 +0530 Subject: [PATCH 06/37] [PBSD-5] Allow production and sandbox credentials to be stored --- Block/Adminhtml/Form/Field/Validation.php | 8 +-- .../Adminhtml/Configuration/Validate.php | 16 ++++-- Gateway/Config/Config.php | 17 ++++++ Model/Adapter/BraintreeAdapter.php | 14 +++-- etc/adminhtml/system.xml | 53 +++++++++++++++++-- etc/config.xml | 2 + view/adminhtml/web/js/system.js | 17 ++++-- 7 files changed, 105 insertions(+), 22 deletions(-) diff --git a/Block/Adminhtml/Form/Field/Validation.php b/Block/Adminhtml/Form/Field/Validation.php index ba9def18..c5a5cd0e 100755 --- a/Block/Adminhtml/Form/Field/Validation.php +++ b/Block/Adminhtml/Form/Field/Validation.php @@ -33,12 +33,6 @@ protected function _getElementHtml(AbstractElement $element): string $title = __('Validate Credentials'); $envId = 'select-groups-braintree-section-groups-braintree-groups-braintree-' . 'required-fields-environment-value'; - $merchantId = 'text-groups-braintree-section-groups-braintree-groups-braintree-' - . 'required-fields-merchant-id-value'; - $publicKeyId = 'password-groups-braintree-section-groups-braintree-groups-braintree-' - . 'required-fields-public-key-value'; - $privateKeyId = 'password-groups-braintree-section-groups-braintree-groups-braintree-' - . 'required-fields-private-key-value'; $storeId = 0; if ($this->getRequest()->getParam('website')) { @@ -58,7 +52,7 @@ protected function _getElementHtml(AbstractElement $element): string type="button" title="{$title}" class="button" - onclick="braintreeValidator.call(this, '{$endpoint}', '{$envId}', '{$merchantId}', '{$publicKeyId}', '{$privateKeyId}')"> + onclick="braintreeValidator.call(this, '{$endpoint}', '{$envId}')"> {$title} TEXT; diff --git a/Controller/Adminhtml/Configuration/Validate.php b/Controller/Adminhtml/Configuration/Validate.php index a8c2d123..b8c68c15 100755 --- a/Controller/Adminhtml/Configuration/Validate.php +++ b/Controller/Adminhtml/Configuration/Validate.php @@ -8,6 +8,7 @@ use Magento\Framework\Controller\ResultFactory; use Magento\Braintree\Gateway\Config\Config; use Magento\Framework\Controller\ResultInterface; +use Magento\Braintree\Model\Adminhtml\Source\Environment; /** * Class Validate @@ -44,19 +45,28 @@ public function execute(): ResultInterface $publicKey = $this->getRequest()->getParam('public_key'); $privateKey = $this->getRequest()->getParam('private_key'); $storeId = $this->getRequest()->getParam('storeId', 0); + $environment = $this->getRequest()->getParam('environment'); if (false !== strpos($publicKey, '*')) { - $publicKey = $this->config->getValue(Config::KEY_PUBLIC_KEY, $storeId); + if ($environment === Environment::ENVIRONMENT_SANDBOX) { + $publicKey = $this->config->getValue(Config::KEY_SANDBOX_PUBLIC_KEY, $storeId); + } else { + $publicKey = $this->config->getValue(Config::KEY_PUBLIC_KEY, $storeId); + } } if (false !== strpos($privateKey, '*')) { - $privateKey = $this->config->getValue(Config::KEY_PRIVATE_KEY, $storeId); + if ($environment === Environment::ENVIRONMENT_SANDBOX) { + $privateKey = $this->config->getValue(Config::KEY_SANDBOX_PRIVATE_KEY, $storeId); + } else { + $privateKey = $this->config->getValue(Config::KEY_PRIVATE_KEY, $storeId); + } } $response = $this->resultFactory->create(ResultFactory::TYPE_JSON); try { - Configuration::environment($this->getRequest()->getParam('environment')); + Configuration::environment($environment); Configuration::merchantId($this->getRequest()->getParam('merchant_id')); Configuration::publicKey($publicKey); Configuration::privateKey($privateKey); diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 03ff9686..0d12bb32 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -10,6 +10,7 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Serialize\Serializer\Json; +use Magento\Braintree\Model\Adminhtml\Source\Environment; use Magento\Braintree\Model\StoreConfigResolver; /** @@ -24,6 +25,10 @@ class Config extends \Magento\Payment\Gateway\Config\Config const KEY_MERCHANT_ACCOUNT_ID = 'merchant_account_id'; const KEY_PUBLIC_KEY = 'public_key'; const KEY_PRIVATE_KEY = 'private_key'; + const KEY_SANDBOX_MERCHANT_ID = 'sandbox_merchant_id'; + const KEY_SANDBOX_MERCHANT_ACCOUNT_ID = 'sandbox_merchant_account_id'; + const KEY_SANDBOX_PUBLIC_KEY = 'sandbox_public_key'; + const KEY_SANDBOX_PRIVATE_KEY = 'sandbox_private_key'; const KEY_COUNTRY_CREDIT_CARD = 'countrycreditcard'; const KEY_CC_TYPES = 'cctypes'; const KEY_CC_TYPES_BRAINTREE_MAPPER = 'cctypes_braintree_mapper'; @@ -280,6 +285,12 @@ public function canSkipAdminFraudProtection(): bool */ public function getMerchantId() { + if ($this->getEnvironment() === Environment::ENVIRONMENT_SANDBOX) { + return $this->getValue( + self::KEY_SANDBOX_MERCHANT_ID, + $this->storeConfigResolver->getStoreId() + ); + } return $this->getValue( self::KEY_MERCHANT_ID, $this->storeConfigResolver->getStoreId() @@ -357,6 +368,12 @@ public function getDynamicDescriptors(): array */ public function getMerchantAccountId() { + if ($this->getEnvironment() === Environment::ENVIRONMENT_SANDBOX) { + return $this->getValue( + self::KEY_SANDBOX_MERCHANT_ACCOUNT_ID, + $this->storeConfigResolver->getStoreId() + ); + } return $this->getValue( self::KEY_MERCHANT_ACCOUNT_ID, $this->storeConfigResolver->getStoreId() diff --git a/Model/Adapter/BraintreeAdapter.php b/Model/Adapter/BraintreeAdapter.php index 426ac35c..9960d6c2 100755 --- a/Model/Adapter/BraintreeAdapter.php +++ b/Model/Adapter/BraintreeAdapter.php @@ -80,18 +80,26 @@ protected function initCredentials() $this->environment(Environment::ENVIRONMENT_SANDBOX); + $merchantId = $this->config->getValue(Config::KEY_SANDBOX_MERCHANT_ID, $storeId); + $publicKey = $this->config->getValue(Config::KEY_SANDBOX_PUBLIC_KEY, $storeId); + $privateKey = $this->config->getValue(Config::KEY_SANDBOX_PRIVATE_KEY, $storeId); + if ($environmentIdentifier === Environment::ENVIRONMENT_PRODUCTION) { $this->environment(Environment::ENVIRONMENT_PRODUCTION); + + $merchantId = $this->config->getValue(Config::KEY_MERCHANT_ID, $storeId); + $publicKey = $this->config->getValue(Config::KEY_PUBLIC_KEY, $storeId); + $privateKey = $this->config->getValue(Config::KEY_PRIVATE_KEY, $storeId); } $this->merchantId( - $this->config->getValue(Config::KEY_MERCHANT_ID, $storeId) + $merchantId ); $this->publicKey( - $this->config->getValue(Config::KEY_PUBLIC_KEY, $storeId) + $publicKey ); $this->privateKey( - $this->config->getValue(Config::KEY_PRIVATE_KEY, $storeId) + $privateKey ); } diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 33ee154e..d1092f5f 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -112,16 +112,64 @@ payment/braintree/merchant_id + + production + + + + + If you don't specify the merchant account to use to process a transaction, Braintree will process it using your default merchant account. + payment/braintree/merchant_account_id + + production + payment/braintree/public_key Magento\Config\Model\Config\Backend\Encrypted + + production + payment/braintree/private_key Magento\Config\Model\Config\Backend\Encrypted + + production + + + + + payment/braintree/sandbox_merchant_id + + sandbox + + + + + If you don't specify the merchant account to use to process a transaction, Braintree will process it using your default merchant account. + payment/braintree/sandbox_merchant_account_id + + sandbox + + + + + payment/braintree/sandbox_public_key + Magento\Config\Model\Config\Backend\Encrypted + + sandbox + + + + + payment/braintree/sandbox_private_key + Magento\Config\Model\Config\Backend\Encrypted + + sandbox + @@ -135,11 +183,6 @@ payment/braintree_cc_vault/title - - - If you don't specify the merchant account to use to process a transaction, Braintree will process it using your default merchant account. - payment/braintree/merchant_account_id - Magento\Config\Model\Config\Source\Yesno diff --git a/etc/config.xml b/etc/config.xml index cbd12db3..29df9e98 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -36,6 +36,8 @@ 0 + + cvv,number avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,riskDataId,riskDataDecision,transactionSource cc_type,cc_number,avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,riskDataId,riskDataDecision,transactionSource diff --git a/view/adminhtml/web/js/system.js b/view/adminhtml/web/js/system.js index 0dde3c5e..cbf37028 100755 --- a/view/adminhtml/web/js/system.js +++ b/view/adminhtml/web/js/system.js @@ -1,9 +1,18 @@ require(['jquery', 'Magento_Ui/js/modal/alert', 'mage/translate'], function ($, alert, $t) { - window.braintreeValidator = function (endpoint, env_id, merch_id, public_id, private_id) { + window.braintreeValidator = function (endpoint, env_id) { env_id = $('[data-ui-id="' + env_id + '"]').val(); - merch_id = $('[data-ui-id="' + merch_id + '"]').val(); - public_id = $('[data-ui-id="' + public_id + '"]').val(); - private_id = $('[data-ui-id="' + private_id + '"]').val(); + + var merch_id = '', public_id = '', private_id = ''; + + if (env_id === 'sandbox') { + merch_id = $('[data-ui-id="text-groups-braintree-section-groups-braintree-groups-braintree-required-fields-sandbox-merchant-id-value"]').val(); + public_id = $('[data-ui-id="password-groups-braintree-section-groups-braintree-groups-braintree-required-fields-sandbox-public-key-value"]').val(); + private_id = $('[data-ui-id="password-groups-braintree-section-groups-braintree-groups-braintree-required-fields-sandbox-private-key-value"]').val(); + } else { + merch_id = $('[data-ui-id="text-groups-braintree-section-groups-braintree-groups-braintree-required-fields-merchant-id-value"]').val(); + public_id = $('[data-ui-id="password-groups-braintree-section-groups-braintree-groups-braintree-required-fields-public-key-value"]').val(); + private_id = $('[data-ui-id="password-groups-braintree-section-groups-braintree-groups-braintree-required-fields-private-key-value"]').val(); + } /* Remove previous success message if present */ if ($(".braintree-credentials-success-message")) { From d28b5f902c684bd8368938c7b0e5e1c70f663226 Mon Sep 17 00:00:00 2001 From: kartik Date: Wed, 29 Jul 2020 13:48:13 +0530 Subject: [PATCH 07/37] Fixed incorrect class name used --- Gateway/Request/VaultDataBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gateway/Request/VaultDataBuilder.php b/Gateway/Request/VaultDataBuilder.php index 0bd6e61b..9e276c28 100755 --- a/Gateway/Request/VaultDataBuilder.php +++ b/Gateway/Request/VaultDataBuilder.php @@ -6,7 +6,7 @@ namespace Magento\Braintree\Gateway\Request; use Magento\Payment\Gateway\Request\BuilderInterface; -use PayPal\Braintree\Gateway\Helper\SubjectReader; +use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Vault\Model\Ui\VaultConfigProvider; /** From 3697f6eb790df48eabdfc8368c5327a78d04fe89 Mon Sep 17 00:00:00 2001 From: kartik Date: Wed, 5 Aug 2020 10:59:47 +0530 Subject: [PATCH 08/37] Fixed wrong amount being sent to PayPal when promotion code applied and Decimal points error for 3dsecure cards --- view/frontend/web/js/view/payment/3d-secure.js | 2 +- view/frontend/web/js/view/payment/method-renderer/paypal.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/view/frontend/web/js/view/payment/3d-secure.js b/view/frontend/web/js/view/payment/3d-secure.js index 3e194b1b..0613f60a 100755 --- a/view/frontend/web/js/view/payment/3d-secure.js +++ b/view/frontend/web/js/view/payment/3d-secure.js @@ -43,7 +43,7 @@ define([ validate: function (context) { var clientInstance = braintree.getApiClient(), state = $.Deferred(), - totalAmount = quote.totals()['base_grand_total'], + totalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2), billingAddress = quote.billingAddress(); // No 3d secure if using CVV verification on vaulted cards diff --git a/view/frontend/web/js/view/payment/method-renderer/paypal.js b/view/frontend/web/js/view/payment/method-renderer/paypal.js index 7ef8ff61..df01ccd6 100644 --- a/view/frontend/web/js/view/payment/method-renderer/paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/paypal.js @@ -126,6 +126,7 @@ define([ quote.totals.subscribe(function () { if (self.grandTotalAmount !== quote.totals()['base_grand_total']) { self.grandTotalAmount = quote.totals()['base_grand_total']; + self.reInitPayPal(); } }); From dd79cbaf66e594004731b88c2e364b3fdca0c828 Mon Sep 17 00:00:00 2001 From: kartik Date: Thu, 6 Aug 2020 11:06:18 +0530 Subject: [PATCH 09/37] [PBSD-30] Fixed 3D secure card verification error of special characters for Name fields --- view/frontend/web/js/view/payment/3d-secure.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/view/frontend/web/js/view/payment/3d-secure.js b/view/frontend/web/js/view/payment/3d-secure.js index 3e194b1b..d81eea79 100755 --- a/view/frontend/web/js/view/payment/3d-secure.js +++ b/view/frontend/web/js/view/payment/3d-secure.js @@ -35,6 +35,15 @@ define([ return 'three_d_secure'; }, + /** + * convert Non-ASCII characters into unicode + * @param str + * @returns {string} + */ + escapeNonAsciiCharacters: function (str) { + return [...str].map(c => /^[\x00-\x7F]$/.test(c) ? c : c.split("").map(a => "\\u" + a.charCodeAt().toString(16).padStart(4, "0")).join("")).join(""); + }, + /** * Validate Braintree payment nonce * @param {Object} context @@ -59,6 +68,9 @@ define([ return state.promise(); } + var firstName = this.escapeNonAsciiCharacters(billingAddress.firstname); + var lastName = this.escapeNonAsciiCharacters(billingAddress.lastname); + fullScreenLoader.startLoader(); var setup3d = function(clientInstance) { @@ -89,8 +101,8 @@ define([ amount: totalAmount, nonce: context.paymentMethodNonce, billingAddress: { - givenName: billingAddress.firstname, - surname: billingAddress.lastname, + givenName: firstName, + surname: lastName, phoneNumber: billingAddress.telephone, streetAddress: billingAddress.street[0], extendedAddress: billingAddress.street[1], From 7460920de9f0a5dff70b017aa3e4d92ab5e4f0e8 Mon Sep 17 00:00:00 2001 From: kartik Date: Thu, 6 Aug 2020 11:50:44 +0530 Subject: [PATCH 10/37] [PBSD-7] Removed China Union Pay(CUP) from list of allowed cards --- Console/VaultMigrate.php | 3 +-- Model/Adminhtml/Source/CcType.php | 23 ++--------------------- README.md | 1 - Test/Unit/Block/FormTest.php | 1 - etc/config.xml | 4 ++-- 5 files changed, 5 insertions(+), 27 deletions(-) diff --git a/Console/VaultMigrate.php b/Console/VaultMigrate.php index 3fe74f70..e2d0d7fa 100644 --- a/Console/VaultMigrate.php +++ b/Console/VaultMigrate.php @@ -47,8 +47,7 @@ class VaultMigrate extends Command 'master-card' => 'MC', 'visa' => 'VI', 'maestro' => 'MI', - 'diners-club' => 'DN', - 'unionpay' => 'CUP' + 'diners-club' => 'DN' ]; /** diff --git a/Model/Adminhtml/Source/CcType.php b/Model/Adminhtml/Source/CcType.php index b93f9d1f..53d2ad60 100755 --- a/Model/Adminhtml/Source/CcType.php +++ b/Model/Adminhtml/Source/CcType.php @@ -11,31 +11,12 @@ */ class CcType extends \Magento\Payment\Model\Source\Cctype { - /** - * List of specific credit card types - * - * @var array - */ - private $specificCardTypesList = [ - 'CUP' => 'China Union Pay' - ]; - /** * @inheritDoc */ public function getAllowedTypes(): array { - return ['VI', 'MC', 'AE', 'DI', 'JCB', 'MI', 'DN', 'CUP']; - } - - /** - * Returns credit cards types - * - * @return array - */ - public function getCcTypeLabelMap(): array - { - return array_merge($this->specificCardTypesList, $this->_paymentConfig->getCcTypes()); + return ['VI', 'MC', 'AE', 'DI', 'JCB', 'MI', 'DN']; } /** @@ -46,7 +27,7 @@ public function toOptionArray(): array $allowed = $this->getAllowedTypes(); $options = []; - foreach ($this->getCcTypeLabelMap() as $code => $name) { + foreach ($this->_paymentConfig->getCcTypes() as $code => $name) { if (in_array($code, $allowed)) { $options[] = ['value' => $code, 'label' => $name]; } diff --git a/README.md b/README.md index 65e470ab..af5df9a9 100755 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ This module overwrites the original Magento Braintree module, to provide additio * JCB * Diners * Maestro - * UnionPay * Restrictions apply. * PayPal * PayPal Credit diff --git a/Test/Unit/Block/FormTest.php b/Test/Unit/Block/FormTest.php index 5b28e6d8..ddf837fa 100644 --- a/Test/Unit/Block/FormTest.php +++ b/Test/Unit/Block/FormTest.php @@ -29,7 +29,6 @@ class FormTest extends \PHPUnit\Framework\TestCase 'MC' => 'MasterCard', 'DI' => 'Discover', 'JBC' => 'JBC', - 'CUP' => 'China Union Pay', 'MI' => 'Maestro', ]; diff --git a/etc/config.xml b/etc/config.xml index cbd12db3..e3edc1ea 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -28,9 +28,9 @@ 1 1 1 - AE,VI,MC,DI,JCB,CUP,DN,MI + AE,VI,MC,DI,JCB,DN,MI 1 - + processing sandbox 0 From a62e3b515271dcde1c82fac90bb0a06fe21bc24a Mon Sep 17 00:00:00 2001 From: kartik Date: Thu, 6 Aug 2020 19:14:27 +0530 Subject: [PATCH 11/37] [PBSD-39] Fixed Venmo browser error on checkout page --- view/frontend/web/js/view/payment/method-renderer/venmo.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/venmo.js b/view/frontend/web/js/view/payment/method-renderer/venmo.js index a9f473f0..23049262 100644 --- a/view/frontend/web/js/view/payment/method-renderer/venmo.js +++ b/view/frontend/web/js/view/payment/method-renderer/venmo.js @@ -121,13 +121,12 @@ define( client: clientInstance, allowNewBrowserTab: false }, function (venmoErr, venmoInstance) { - if (venmoErr) { - self.setErrorMsg($t('Error initializing Venmo: %1').replace('%1', venmoErr)); + if (!venmoInstance.isBrowserSupported()) { return; } - if (!venmoInstance.isBrowserSupported()) { - self.setErrorMsg($t('Browser does not support Venmo.')); + if (venmoErr) { + self.setErrorMsg($t('Error initializing Venmo: %1').replace('%1', venmoErr)); return; } From 746ec429d526b5b56fe4f52b38d12938951d10de Mon Sep 17 00:00:00 2001 From: kartik Date: Fri, 7 Aug 2020 15:36:59 +0530 Subject: [PATCH 12/37] [PBSD-41] PayPal Credit field will only be available if Merchant Country is either US or UK. --- Block/System/Config/Form/Fieldset.php | 6 +++++- etc/adminhtml/system.xml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Block/System/Config/Form/Fieldset.php b/Block/System/Config/Form/Fieldset.php index eb390c7a..b064462e 100644 --- a/Block/System/Config/Form/Fieldset.php +++ b/Block/System/Config/Form/Fieldset.php @@ -45,7 +45,7 @@ public function __construct( } /** - * Remove UK specific fields from the form when on a non-UK merchant country + * Remove US & UK specific fields from the form if merchant country is not UK or US. * * @inheritDoc */ @@ -68,7 +68,11 @@ protected function _getChildrenElementsHtml(AbstractElement $element): string // ); } + // Only available to GB and US if ($locale !== 'gb' && $locale !== 'us') { + $element->removeField( + 'payment_' . $locale . '_braintree_section_braintree_braintree_paypal_credit_active' + ); $element->removeField( 'payment_other_braintree_section_braintree_braintree_paypal_credit_active' ); diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 33ee154e..f5cc4bde 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -36,7 +36,7 @@ Magento\Config\Model\Config\Source\Yesno payment/braintree_paypal_credit/active - PayPal Credit is currently only available in the United States and United Kingdom. PayPal Credit will be disabled if the selected value for the Merchant Country field is not US or UK. + PayPal Credit is currently only available in the United States and United Kingdom. PayPal Credit will be disabled if the selected value for the Merchant Country field is not US or UK. This field is only available if Merchant Country is US or UK. From 191652f85f38b6ceaa92ff2f4e8cd25a336aa05d Mon Sep 17 00:00:00 2001 From: kartik Date: Fri, 14 Aug 2020 14:50:26 +0530 Subject: [PATCH 13/37] Added code to validate payment method before re-initializing PayPal --- view/frontend/web/js/view/payment/method-renderer/paypal.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/paypal.js b/view/frontend/web/js/view/payment/method-renderer/paypal.js index df01ccd6..8fb686c9 100644 --- a/view/frontend/web/js/view/payment/method-renderer/paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/paypal.js @@ -126,7 +126,11 @@ define([ quote.totals.subscribe(function () { if (self.grandTotalAmount !== quote.totals()['base_grand_total']) { self.grandTotalAmount = quote.totals()['base_grand_total']; - self.reInitPayPal(); + var methodCode = quote.paymentMethod(); + + if (methodCode === 'braintree_paypal' || methodCode === 'braintree_paypal_vault') { + self.reInitPayPal(); + } } }); From 12bd129b52040e9623366b722f6af3930140735f Mon Sep 17 00:00:00 2001 From: kartik Date: Fri, 28 Aug 2020 21:14:26 +0530 Subject: [PATCH 14/37] [PBSD-45/BUNDLE-2731] Fixed Braintree Merchant Account ID configuration field required issue --- Gateway/Config/Config.php | 7 ------- etc/adminhtml/system.xml | 23 ++++++----------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 0d12bb32..a7480a5e 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -26,7 +26,6 @@ class Config extends \Magento\Payment\Gateway\Config\Config const KEY_PUBLIC_KEY = 'public_key'; const KEY_PRIVATE_KEY = 'private_key'; const KEY_SANDBOX_MERCHANT_ID = 'sandbox_merchant_id'; - const KEY_SANDBOX_MERCHANT_ACCOUNT_ID = 'sandbox_merchant_account_id'; const KEY_SANDBOX_PUBLIC_KEY = 'sandbox_public_key'; const KEY_SANDBOX_PRIVATE_KEY = 'sandbox_private_key'; const KEY_COUNTRY_CREDIT_CARD = 'countrycreditcard'; @@ -368,12 +367,6 @@ public function getDynamicDescriptors(): array */ public function getMerchantAccountId() { - if ($this->getEnvironment() === Environment::ENVIRONMENT_SANDBOX) { - return $this->getValue( - self::KEY_SANDBOX_MERCHANT_ACCOUNT_ID, - $this->storeConfigResolver->getStoreId() - ); - } return $this->getValue( self::KEY_MERCHANT_ACCOUNT_ID, $this->storeConfigResolver->getStoreId() diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index d1092f5f..8e3a8a5a 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -116,14 +116,6 @@ production - - - If you don't specify the merchant account to use to process a transaction, Braintree will process it using your default merchant account. - payment/braintree/merchant_account_id - - production - - payment/braintree/public_key @@ -147,14 +139,6 @@ sandbox - - - If you don't specify the merchant account to use to process a transaction, Braintree will process it using your default merchant account. - payment/braintree/sandbox_merchant_account_id - - sandbox - - payment/braintree/sandbox_public_key @@ -176,13 +160,18 @@ Magento\Braintree\Block\Adminhtml\Form\Field\Validation - + Magento\Config\Block\System\Config\Form\Fieldset payment/braintree_cc_vault/title + + + If you don't specify the merchant account to use to process a transaction, Braintree will process it using your default merchant account. + payment/braintree/merchant_account_id + Magento\Config\Model\Config\Source\Yesno From 2e53873fa65062d36bb6e195cf8f96edb1e507b7 Mon Sep 17 00:00:00 2001 From: Dima Date: Mon, 7 Sep 2020 15:45:39 +0300 Subject: [PATCH 15/37] partial invoice --- Gateway/Command/CaptureStrategyCommand.php | 18 +++++++++++++-- Gateway/Config/CanVoidHandler.php | 10 ++++++-- .../TransactionSubmitForPartialSettlement.php | 23 +++++++++++++++++++ Model/Adapter/BraintreeAdapter.php | 10 ++++++++ etc/di.xml | 12 ++++++++++ 5 files changed, 69 insertions(+), 4 deletions(-) create mode 100755 Gateway/Http/Client/TransactionSubmitForPartialSettlement.php diff --git a/Gateway/Command/CaptureStrategyCommand.php b/Gateway/Command/CaptureStrategyCommand.php index 68f66467..a924d131 100755 --- a/Gateway/Command/CaptureStrategyCommand.php +++ b/Gateway/Command/CaptureStrategyCommand.php @@ -19,6 +19,7 @@ use Magento\Sales\Api\Data\OrderPaymentInterface; use Magento\Sales\Api\TransactionRepositoryInterface; use Magento\Sales\Api\Data\TransactionInterface; +use Magento\Braintree\Model\Ui\PayPal\ConfigProvider as PaypalConfigProvider; /** * Class CaptureStrategyCommand @@ -36,6 +37,11 @@ class CaptureStrategyCommand implements CommandInterface */ const CAPTURE = 'settlement'; + /** + * Braintree partial capture command + */ + const PARTIAL_CAPTURE = 'partial_capture'; + /** * Braintree vault capture command */ @@ -116,18 +122,20 @@ public function execute(array $commandSubject) /** @var OrderPaymentInterface $paymentInfo */ $paymentInfo = $paymentDO->getPayment(); + $amount = $commandSubject['amount']; ContextHelper::assertOrderPayment($paymentInfo); - $command = $this->getCommand($paymentInfo); + $command = $this->getCommand($paymentInfo, $amount); $this->commandPool->get($command)->execute($commandSubject); } /** * Get execution command name * @param OrderPaymentInterface $payment + * @param float $amount * @return string */ - private function getCommand(OrderPaymentInterface $payment): string + private function getCommand(OrderPaymentInterface $payment, $amount): string { // if auth transaction is not exists execute authorize&capture command $existsCapture = $this->isExistsCaptureTransaction($payment); @@ -136,6 +144,12 @@ private function getCommand(OrderPaymentInterface $payment): string return self::SALE; } + // do partial capture for authorization transaction only braintree PayPal + if ($amount < $payment->getAmountAuthorized() && !$this->isExpiredAuthorization($payment) + && ($payment->getMethod() == PaypalConfigProvider::PAYPAL_CODE)) { + return self::PARTIAL_CAPTURE; + } + // do capture for authorization transaction if (!$existsCapture && !$this->isExpiredAuthorization($payment)) { return self::CAPTURE; diff --git a/Gateway/Config/CanVoidHandler.php b/Gateway/Config/CanVoidHandler.php index 3b7cc606..573c7a09 100755 --- a/Gateway/Config/CanVoidHandler.php +++ b/Gateway/Config/CanVoidHandler.php @@ -42,8 +42,14 @@ public function __construct( public function handle(array $subject, $storeId = null) { $paymentDO = $this->subjectReader->readPayment($subject); - + $canCaptureFlag = true; $payment = $paymentDO->getPayment(); - return $payment instanceof Payment && !(bool)$payment->getAmountPaid(); + if ((bool)$payment->getAmountPaid()) { + $canCaptureFlag = false; + } + if ($payment->getAmountPaid() < $payment->getAmountAuthorized() && (bool)$payment->getAmountPaid()) { + $canCaptureFlag = true; + } + return $payment instanceof Payment && $canCaptureFlag; } } diff --git a/Gateway/Http/Client/TransactionSubmitForPartialSettlement.php b/Gateway/Http/Client/TransactionSubmitForPartialSettlement.php new file mode 100755 index 00000000..77c3ff6b --- /dev/null +++ b/Gateway/Http/Client/TransactionSubmitForPartialSettlement.php @@ -0,0 +1,23 @@ +adapter->submitForPartialSettlement( + $data[CaptureDataBuilder::TRANSACTION_ID], + $data[PaymentDataBuilder::AMOUNT] + ); + } +} diff --git a/Model/Adapter/BraintreeAdapter.php b/Model/Adapter/BraintreeAdapter.php index 426ac35c..4f49610a 100755 --- a/Model/Adapter/BraintreeAdapter.php +++ b/Model/Adapter/BraintreeAdapter.php @@ -205,6 +205,16 @@ public function submitForSettlement($transactionId, $amount = null) return Transaction::submitForSettlement($transactionId, $amount); } + /** + * @param string $transactionId + * @param null|float $amount + * @return Successful|Error + */ + public function submitForPartialSettlement($transactionId, $amount = null) + { + return Transaction::submitForPartialSettlement($transactionId, $amount); + } + /** * @param string $transactionId * @return Successful|Error diff --git a/etc/di.xml b/etc/di.xml index 700fa81e..ce2afcc0 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -160,6 +160,7 @@ BraintreePayPalAuthorizeCommand BraintreePayPalSaleCommand BraintreePayPalCaptureStrategyCommand + BraintreePartialCaptureCommand BraintreeCaptureCommand BraintreePayPalVaultAuthorizeCommand BraintreePayPalVaultSaleCommand @@ -255,6 +256,17 @@ Magento\Braintree\Gateway\Validator\ResponseValidator + + + + BraintreeCaptureRequest + Magento\Braintree\Gateway\Http\TransferFactory + Magento\Braintree\Gateway\Http\Client\TransactionSubmitForPartialSettlement + Magento\Braintree\Gateway\Response\TransactionIdHandler + Magento\Braintree\Gateway\Validator\ResponseValidator + + + From 499db6bebbac7480eb2abbe54a7010270110eb7a Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Thu, 1 Oct 2020 22:02:45 +0530 Subject: [PATCH 16/37] [PBSD-60] Added ECI Flag to the order payment details for the Braintree Credit Card 3D secure transactions --- .../Response/ThreeDSecureDetailsHandler.php | 29 +++++++++++++++++++ etc/config.xml | 4 +-- i18n/en_US.csv | 1 + 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Gateway/Response/ThreeDSecureDetailsHandler.php b/Gateway/Response/ThreeDSecureDetailsHandler.php index 09ace55b..21da5d0d 100755 --- a/Gateway/Response/ThreeDSecureDetailsHandler.php +++ b/Gateway/Response/ThreeDSecureDetailsHandler.php @@ -14,6 +14,7 @@ /** * Class ThreeDSecureDetailsHandler + * @package Magento\Braintree\Gateway\Response */ class ThreeDSecureDetailsHandler implements HandlerInterface { @@ -21,6 +22,17 @@ class ThreeDSecureDetailsHandler implements HandlerInterface const LIABILITY_SHIFT_POSSIBLE = 'liabilityShiftPossible'; + const ECI_FLAG = 'eciFlag'; + + const ECI_ACCEPTED_VALUES = [ + '00' => 'Failed', + '01' => 'Attempted', + '02' => 'Success', + '07' => 'Failed', + '06' => 'Attempted', + '05' => 'Success' + ]; + /** * @var SubjectReader */ @@ -64,5 +76,22 @@ public function handle(array $handlingSubject, array $response) $payment->setAdditionalInformation(self::LIABILITY_SHIFTED, $info->liabilityShifted ? 'Yes' : 'No'); $shiftPossible = $info->liabilityShiftPossible ? 'Yes' : 'No'; $payment->setAdditionalInformation(self::LIABILITY_SHIFT_POSSIBLE, $shiftPossible); + + $eciFlag = $this->getEciFlagInformation($info->eciFlag); + if ($eciFlag !== '') { + $payment->setAdditionalInformation(self::ECI_FLAG, $eciFlag); + } + } + + /** + * @param $eciFlagValue + * @return mixed|string + */ + public function getEciFlagInformation($eciFlagValue) + { + if ($eciFlagValue !== NULL && array_key_exists($eciFlagValue, self::ECI_ACCEPTED_VALUES)) { + return self::ECI_ACCEPTED_VALUES[$eciFlagValue]; + } + return ''; } } diff --git a/etc/config.xml b/etc/config.xml index cbd12db3..50450760 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -37,8 +37,8 @@ cvv,number - avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,riskDataId,riskDataDecision,transactionSource - cc_type,cc_number,avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,riskDataId,riskDataDecision,transactionSource + avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,eciFlag,riskDataId,riskDataDecision,transactionSource + cc_type,cc_number,avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,eciFlag,riskDataId,riskDataDecision,transactionSource 208.75.112.0/22,209.81.12.0/24 diff --git a/i18n/en_US.csv b/i18n/en_US.csv index 51e8c687..0f4fb6d7 100755 --- a/i18n/en_US.csv +++ b/i18n/en_US.csv @@ -140,6 +140,7 @@ Debug,Debug "braintree", "Braintree" "liabilityShifted", "Liability Shifted" "liabilityShiftPossible", "Liability Shift Possible" +"eciFlag", "ECI Flag" "riskDataId", "Risk ID" "riskDataDecision", "Risk Decision" "paymentId", "Payment Id" From 0b15fbae2de83ef5ad65e1db0525133ef382083f Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Thu, 15 Oct 2020 21:42:59 +0530 Subject: [PATCH 17/37] [BUNDLE 2747/PBSD-58] Implemented Instant Purchase functionality --- .../CreditCard/AvailabilityChecker.php | 47 +++++++++++++++ .../CreditCard/TokenFormatter.php | 60 +++++++++++++++++++ .../InstantPurchase/PayPal/TokenFormatter.php | 37 ++++++++++++ .../PaymentAdditionalInformationProvider.php | 48 +++++++++++++++ etc/config.xml | 9 +++ 5 files changed, 201 insertions(+) create mode 100644 Model/InstantPurchase/CreditCard/AvailabilityChecker.php create mode 100644 Model/InstantPurchase/CreditCard/TokenFormatter.php create mode 100644 Model/InstantPurchase/PayPal/TokenFormatter.php create mode 100644 Model/InstantPurchase/PaymentAdditionalInformationProvider.php diff --git a/Model/InstantPurchase/CreditCard/AvailabilityChecker.php b/Model/InstantPurchase/CreditCard/AvailabilityChecker.php new file mode 100644 index 00000000..4058b4cf --- /dev/null +++ b/Model/InstantPurchase/CreditCard/AvailabilityChecker.php @@ -0,0 +1,47 @@ +config = $config; + } + + /** + * @inheritdoc + */ + public function isAvailable(): bool + { + if ($this->config->isVerify3DSecure()) { + // Support of 3D secure has not been implemented for instant purchase yet. + return false; + } + + return true; + } +} diff --git a/Model/InstantPurchase/CreditCard/TokenFormatter.php b/Model/InstantPurchase/CreditCard/TokenFormatter.php new file mode 100644 index 00000000..6c13b0ba --- /dev/null +++ b/Model/InstantPurchase/CreditCard/TokenFormatter.php @@ -0,0 +1,60 @@ + 'American Express', + 'VI' => 'Visa', + 'MC' => 'MasterCard', + 'DI' => 'Discover', + 'JBC' => 'JBC', + 'MI' => 'Maestro', + ]; + + /** + * @inheritdoc + */ + public function formatPaymentToken(PaymentTokenInterface $paymentToken): string + { + $details = json_decode($paymentToken->getTokenDetails() ?: '{}', true); + if (!isset($details['type'], $details['maskedCC'], $details['expirationDate'])) { + throw new \InvalidArgumentException('Invalid Braintree credit card token details.'); + } + + if (isset(self::$baseCardTypes[$details['type']])) { + $ccType = self::$baseCardTypes[$details['type']]; + } else { + $ccType = $details['type']; + } + + $formatted = sprintf( + '%s: %s, %s: %s (%s: %s)', + __('Credit Card'), + $ccType, + __('ending'), + $details['maskedCC'], + __('expires'), + $details['expirationDate'] + ); + + return $formatted; + } +} diff --git a/Model/InstantPurchase/PayPal/TokenFormatter.php b/Model/InstantPurchase/PayPal/TokenFormatter.php new file mode 100644 index 00000000..3eed7fb0 --- /dev/null +++ b/Model/InstantPurchase/PayPal/TokenFormatter.php @@ -0,0 +1,37 @@ +getTokenDetails() ?: '{}', true); + if (!isset($details['payerEmail'])) { + throw new \InvalidArgumentException('Invalid Braintree PayPal token details.'); + } + + $formatted = sprintf( + '%s: %s', + __('PayPal'), + $details['payerEmail'] + ); + + return $formatted; + } +} diff --git a/Model/InstantPurchase/PaymentAdditionalInformationProvider.php b/Model/InstantPurchase/PaymentAdditionalInformationProvider.php new file mode 100644 index 00000000..403f75e5 --- /dev/null +++ b/Model/InstantPurchase/PaymentAdditionalInformationProvider.php @@ -0,0 +1,48 @@ +getPaymentNonceCommand = $getPaymentNonceCommand; + } + + /** + * @inheritdoc + */ + public function getAdditionalInformation(PaymentTokenInterface $paymentToken): array + { + $paymentMethodNonce = $this->getPaymentNonceCommand->execute([ + PaymentTokenInterface::CUSTOMER_ID => $paymentToken->getCustomerId(), + PaymentTokenInterface::PUBLIC_HASH => $paymentToken->getPublicHash(), + ])->get()['paymentMethodNonce']; + + return [ + 'payment_method_nonce' => $paymentMethodNonce, + ]; + } +} diff --git a/etc/config.xml b/etc/config.xml index dbc5d3ec..342b7c54 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -97,12 +97,21 @@ BraintreeCreditCardVaultFacade Stored Cards + + Magento\Braintree\Model\InstantPurchase\CreditCard\AvailabilityChecker + Magento\Braintree\Model\InstantPurchase\CreditCard\TokenFormatter + Magento\Braintree\Model\InstantPurchase\PaymentAdditionalInformationProvider + braintree_group BraintreePayPalVaultFacade Stored Accounts (PayPal) 1 + + Magento\Braintree\Model\InstantPurchase\PayPal\TokenFormatter + Magento\Braintree\Model\InstantPurchase\PaymentAdditionalInformationProvider + braintree_group From f1bf0d4f74e6bb109c8d19dbd04c02a7a45946f5 Mon Sep 17 00:00:00 2001 From: Dima Date: Wed, 9 Dec 2020 12:47:54 +0200 Subject: [PATCH 18/37] show final price on product page --- Block/Paypal/ProductPage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Block/Paypal/ProductPage.php b/Block/Paypal/ProductPage.php index 384c9ba2..84912604 100644 --- a/Block/Paypal/ProductPage.php +++ b/Block/Paypal/ProductPage.php @@ -109,7 +109,7 @@ public function getAmount(): float return $groupedProducts[0]->getPrice(); } - return $product->getPrice(); + return $product->getFinalPrice(); } return 100; // TODO There must be a better return value than this? From f75f43239316b1de284478807876ca5a26d25c43 Mon Sep 17 00:00:00 2001 From: Dima Date: Thu, 17 Dec 2020 12:10:55 +0200 Subject: [PATCH 19/37] create new version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c2db2ee8..89dd15b4 100755 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "gene/module-braintree", "description": "Fork from the Magento Braintree 2.2.0 module by Gene Commerce for PayPal.", - "version": "4.0.4", + "version": "4.0.6", "type": "magento2-module", "license": "proprietary", "require": { From e2267605f5af7106e037fe819a231942f49c8593 Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Fri, 18 Dec 2020 22:13:20 +0530 Subject: [PATCH 20/37] [PBSD-91] Fixed 3rd line of street field not being sent to Braintree issue --- Gateway/Data/Order/OrderAdapter.php | 24 ++++------------ Gateway/Request/AddressDataBuilder.php | 40 +++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/Gateway/Data/Order/OrderAdapter.php b/Gateway/Data/Order/OrderAdapter.php index c8405127..e7282f85 100644 --- a/Gateway/Data/Order/OrderAdapter.php +++ b/Gateway/Data/Order/OrderAdapter.php @@ -6,8 +6,6 @@ namespace Magento\Braintree\Gateway\Data\Order; use Magento\Payment\Gateway\Data\AddressAdapterInterface; -use Magento\Payment\Gateway\Data\Order\AddressAdapter; -use Magento\Payment\Gateway\Data\Order\AddressAdapterFactory; use Magento\Payment\Gateway\Data\OrderAdapterInterface; use Magento\Sales\Model\Order; @@ -21,21 +19,13 @@ class OrderAdapter implements OrderAdapterInterface */ private $order; - /** - * @var AddressAdapter - */ - private $addressAdapterFactory; - /** * @param Order $order - * @param AddressAdapterFactory $addressAdapterFactory */ public function __construct( - Order $order, - AddressAdapterFactory $addressAdapterFactory + Order $order ) { $this->order = $order; - $this->addressAdapterFactory = $addressAdapterFactory; } /** @@ -71,14 +61,12 @@ public function getCustomerId() /** * Returns billing address * - * @return AddressAdapterInterface|null + * @return AddressAdapterInterface|\Magento\Sales\Api\Data\OrderAddressInterface|null */ public function getBillingAddress() { if ($this->order->getBillingAddress()) { - return $this->addressAdapterFactory->create( - ['address' => $this->order->getBillingAddress()] - ); + return $this->order->getBillingAddress(); } return null; @@ -87,14 +75,12 @@ public function getBillingAddress() /** * Returns shipping address * - * @return AddressAdapterInterface|null + * @return AddressAdapterInterface|Order\Address|null */ public function getShippingAddress() { if ($this->order->getShippingAddress()) { - return $this->addressAdapterFactory->create( - ['address' => $this->order->getShippingAddress()] - ); + return $this->order->getShippingAddress(); } return null; diff --git a/Gateway/Request/AddressDataBuilder.php b/Gateway/Request/AddressDataBuilder.php index 9daba4b8..0e3ba09f 100755 --- a/Gateway/Request/AddressDataBuilder.php +++ b/Gateway/Request/AddressDataBuilder.php @@ -102,12 +102,28 @@ public function build(array $buildSubject): array $billingAddress = $order->getBillingAddress(); if ($billingAddress) { + $street = $billingAddress->getStreet(); + $streetAddress = isset($street[0]) ? $street[0] : ''; + $streetAddress1 = isset($street[1]) ? $street[1] : ''; + $streetAddress2 = isset($street[2]) ? $street[2] : ''; + $streetAddress3 = isset($street[3]) ? $street[3] : ''; + + $extendedAddress = $streetAddress1; + if (!empty($streetAddress1)) { + if (!empty($streetAddress2)) { + $extendedAddress .= ", " . $streetAddress2; + } + if (!empty($streetAddress3)) { + $extendedAddress .= ", " . $streetAddress2 . ", " . $streetAddress3; + } + } + $result[self::BILLING_ADDRESS] = [ self::FIRST_NAME => $billingAddress->getFirstname(), self::LAST_NAME => $billingAddress->getLastname(), self::COMPANY => $billingAddress->getCompany(), - self::STREET_ADDRESS => $billingAddress->getStreetLine1(), - self::EXTENDED_ADDRESS => $billingAddress->getStreetLine2(), + self::STREET_ADDRESS => $streetAddress, + self::EXTENDED_ADDRESS => $extendedAddress, self::LOCALITY => $billingAddress->getCity(), self::REGION => $billingAddress->getRegionCode(), self::POSTAL_CODE => $billingAddress->getPostcode(), @@ -117,12 +133,28 @@ public function build(array $buildSubject): array $shippingAddress = $order->getShippingAddress(); if ($shippingAddress) { + $street = $shippingAddress->getStreet(); + $streetAddress = isset($street[0]) ? $street[0] : ''; + $streetAddress1 = isset($street[1]) ? $street[1] : ''; + $streetAddress2 = isset($street[2]) ? $street[2] : ''; + $streetAddress3 = isset($street[3]) ? $street[3] : ''; + + $extendedAddress = $streetAddress1; + if (!empty($streetAddress1)) { + if (!empty($streetAddress2)) { + $extendedAddress .= ", " . $streetAddress2; + } + if (!empty($streetAddress3)) { + $extendedAddress .= ", " . $streetAddress2 . ", " . $streetAddress3; + } + } + $result[self::SHIPPING_ADDRESS] = [ self::FIRST_NAME => $shippingAddress->getFirstname(), self::LAST_NAME => $shippingAddress->getLastname(), self::COMPANY => $shippingAddress->getCompany(), - self::STREET_ADDRESS => $shippingAddress->getStreetLine1(), - self::EXTENDED_ADDRESS => $shippingAddress->getStreetLine2(), + self::STREET_ADDRESS => $streetAddress, + self::EXTENDED_ADDRESS => $extendedAddress, self::LOCALITY => $shippingAddress->getCity(), self::REGION => $shippingAddress->getRegionCode(), self::POSTAL_CODE => $shippingAddress->getPostcode(), From a91aece069dac2c7b6b40f7b019dbeb4385507c0 Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Fri, 18 Dec 2020 23:18:16 +0530 Subject: [PATCH 21/37] Implemented code changes --- Gateway/Request/AddressDataBuilder.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gateway/Request/AddressDataBuilder.php b/Gateway/Request/AddressDataBuilder.php index 0e3ba09f..0aa92ad3 100755 --- a/Gateway/Request/AddressDataBuilder.php +++ b/Gateway/Request/AddressDataBuilder.php @@ -111,10 +111,10 @@ public function build(array $buildSubject): array $extendedAddress = $streetAddress1; if (!empty($streetAddress1)) { if (!empty($streetAddress2)) { - $extendedAddress .= ", " . $streetAddress2; + $extendedAddress = $streetAddress1 . ", " . $streetAddress2; } if (!empty($streetAddress3)) { - $extendedAddress .= ", " . $streetAddress2 . ", " . $streetAddress3; + $extendedAddress = $streetAddress1 . ", " . $streetAddress2 . ", " . $streetAddress3; } } @@ -142,10 +142,10 @@ public function build(array $buildSubject): array $extendedAddress = $streetAddress1; if (!empty($streetAddress1)) { if (!empty($streetAddress2)) { - $extendedAddress .= ", " . $streetAddress2; + $extendedAddress = $streetAddress1 . ", " . $streetAddress2; } if (!empty($streetAddress3)) { - $extendedAddress .= ", " . $streetAddress2 . ", " . $streetAddress3; + $extendedAddress = $streetAddress1 . ", " . $streetAddress2 . ", " . $streetAddress3; } } From 155b117ea73c710d7b363f8383c887d9ac663e9f Mon Sep 17 00:00:00 2001 From: Dima Date: Mon, 21 Dec 2020 12:22:12 +0200 Subject: [PATCH 22/37] Paypal Currency Error when user tried to place order from Card page --- view/frontend/web/js/paypal/button.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/view/frontend/web/js/paypal/button.js b/view/frontend/web/js/paypal/button.js index 9ae2ace0..3a23efdf 100644 --- a/view/frontend/web/js/paypal/button.js +++ b/view/frontend/web/js/paypal/button.js @@ -41,7 +41,7 @@ define( onError: null }, - init: function (token) { + init: function (token, currency) { buttonIds = []; $('.action-braintree-paypal-logo').each(function () { if(!$(this).hasClass( "button-loaded" )) { @@ -51,11 +51,11 @@ define( }); if(buttonIds.length > 0){ - this.loadSDK(token); + this.loadSDK(token, currency); } }, - loadSDK: function (token) { + loadSDK: function (token, currency) { braintree.create({ authorization: token }, function (clientErr, clientInstance) { @@ -80,6 +80,7 @@ define( } else { paypalCheckoutInstance.loadPayPalSDK({ components: 'buttons,messages,funding-eligibility', + currency: currency, }, function () { this.renderpayPalButtons(buttonIds, paypalCheckoutInstance) }.bind(this)); From ea1dbf8f0a6641b3cd1510a8bca855ec3d6e728e Mon Sep 17 00:00:00 2001 From: Dima Date: Mon, 21 Dec 2020 12:24:00 +0200 Subject: [PATCH 23/37] Paypal Currency Error when user tried to place order from Card page --- view/frontend/templates/paypal/button.phtml | 2 +- view/frontend/templates/paypal/product_page.phtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/view/frontend/templates/paypal/button.phtml b/view/frontend/templates/paypal/button.phtml index 96390bde..b70a8063 100644 --- a/view/frontend/templates/paypal/button.phtml +++ b/view/frontend/templates/paypal/button.phtml @@ -23,7 +23,7 @@ try { 'jquery' ], function (button, $) { $(function () { - button.init('getClientToken() ?>'); + button.init('getClientToken() ?>', 'escapeHtmlAttr($block->getCurrency()) ?>'); }) }) diff --git a/view/frontend/templates/paypal/product_page.phtml b/view/frontend/templates/paypal/product_page.phtml index cce85f59..a5619855 100644 --- a/view/frontend/templates/paypal/product_page.phtml +++ b/view/frontend/templates/paypal/product_page.phtml @@ -25,7 +25,7 @@ try { 'jquery' ], function (button, $) { $(function () { - button.init('getClientToken() ?>'); + button.init('getClientToken() ?>', 'escapeHtmlAttr($block->getCurrency()) ?>'); }) }) From 02533ac00b6f10ada0344c98355bc7f4dbc8f603 Mon Sep 17 00:00:00 2001 From: Dima Date: Tue, 22 Dec 2020 12:41:13 +0200 Subject: [PATCH 24/37] BNPL latest features --- Block/Paypal/Button.php | 14 +- Gateway/Config/PayPalPayLater/Config.php | 28 ++- Model/Ui/PayPal/ConfigProvider.php | 3 +- etc/adminhtml/system.xml | 38 ++- etc/config.xml | 9 +- view/frontend/layout/checkout_index_index.xml | 3 - view/frontend/templates/paypal/button.phtml | 42 ++-- .../templates/paypal/product_page.phtml | 44 ++-- view/frontend/web/js/paypal/button.js | 27 +- .../frontend/web/js/view/payment/braintree.js | 16 -- .../payment/method-renderer/paypal-credit.js | 33 --- .../js/view/payment/method-renderer/paypal.js | 231 ++++++++++-------- .../web/template/payment/paypal-credit.html | 55 ----- .../frontend/web/template/payment/paypal.html | 16 +- 14 files changed, 298 insertions(+), 261 deletions(-) delete mode 100644 view/frontend/web/js/view/payment/method-renderer/paypal-credit.js delete mode 100644 view/frontend/web/template/payment/paypal-credit.html diff --git a/Block/Paypal/Button.php b/Block/Paypal/Button.php index d1147908..89b5b5ec 100644 --- a/Block/Paypal/Button.php +++ b/Block/Paypal/Button.php @@ -181,11 +181,21 @@ public function isPayLaterActive(): bool } /** + * @param string $type * @return bool */ - public function isPayLaterMessageActive(): bool + public function isPayLaterMessageActive($type): bool { - return $this->payPalPayLaterConfig->isMessageActive(); + return $this->payPalPayLaterConfig->isMessageActive($type); + } + + /** + * @param string $type + * @return bool + */ + public function isPayLaterButtonActive($type): bool + { + return $this->payPalPayLaterConfig->isButtonActive($type); } /** diff --git a/Gateway/Config/PayPalPayLater/Config.php b/Gateway/Config/PayPalPayLater/Config.php index 927aa0e0..afc7de20 100644 --- a/Gateway/Config/PayPalPayLater/Config.php +++ b/Gateway/Config/PayPalPayLater/Config.php @@ -122,17 +122,18 @@ public function isActive(): bool /** * Get Paypal pay later message configuration status + * @param string $type * * @return bool */ - public function isMessageActive(): bool + public function isMessageActive($type): bool { $paypalActive = $this->getConfigValue("payment/braintree_paypal/active"); $paypalPayLaterActive = $this->getConfigValue("payment/braintree_paypal_paylater/active"); - $paypalPayLaterMessageActive = $this->getConfigValue("payment/braintree_paypal/message_productpage_enabled"); + $paypalPayLaterMessageActive = $this->getConfigValue("payment/braintree_paypal/message_" . $type . "_enable"); // If PayPal or PayPal Pay Later is disabled in the admin - if (!$paypalActive || !$paypalPayLaterActive || !$paypalPayLaterMessageActive) { + if (!$paypalActive || !$paypalPayLaterActive || !$paypalPayLaterMessageActive || $this->IsPayPalVaultActive()) { return false; } @@ -144,9 +145,30 @@ public function isMessageActive(): bool return (bool) $paypalPayLaterMessageActive; } + /** + * Get Paypal pay later message configuration status + * @param string $type + * + * @return bool + */ + public function isButtonActive($type): bool + { + $paypalActive = $this->getConfigValue("payment/braintree_paypal/active"); + $paypalPayLaterActive = $this->getConfigValue("payment/braintree_paypal_paylater/active"); + $paypalPayLaterButtonActive = $this->getConfigValue("payment/braintree_paypal/button_paylater_" . $type . "_enable"); + // If PayPal or PayPal Pay Later is disabled in the admin + if (!$paypalActive || !$paypalPayLaterActive || !$paypalPayLaterButtonActive) { + return false; + } + // Only allowed on US + if (!$this->isUS()) { + return false; + } + return (bool) $paypalPayLaterButtonActive; + } /** * Merchant Country set to US diff --git a/Model/Ui/PayPal/ConfigProvider.php b/Model/Ui/PayPal/ConfigProvider.php index b27da592..9fc1543f 100644 --- a/Model/Ui/PayPal/ConfigProvider.php +++ b/Model/Ui/PayPal/ConfigProvider.php @@ -104,7 +104,7 @@ public function getConfig(): array ], self::PAYPAL_PAYLATER_CODE => [ - 'isActive' => $this->payLaterConfig->isActive(), + 'isActive' => $this->payLaterConfig->isButtonActive('checkout'), 'title' => __('PayPal PayLater'), 'isAllowShippingAddressOverride' => $this->config->isAllowToEditShippingAddress(), 'merchantName' => $this->config->getMerchantName(), @@ -112,6 +112,7 @@ public function getConfig(): array 'paymentAcceptanceMarkSrc' => 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/ppc-acceptance-medium.png', 'paymentIcon' => $this->config->getPayPalIcon(), + 'isMessageActive' => $this->payLaterConfig->isMessageActive('checkout'), 'style' => [ 'shape' => $this->config->getButtonShape(Config::BUTTON_AREA_CHECKOUT), 'size' => $this->config->getButtonSize(Config::BUTTON_AREA_CHECKOUT), diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 1aadb59f..07309e3f 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -473,6 +473,20 @@ Magento\Config\Block\System\Config\Form\Fieldset + + + Magento\Config\Model\Config\Source\Yesno + payment/braintree_paypal/button_paylater_cart_enable + + + + Magento\Config\Model\Config\Source\Yesno + payment/braintree_paypal/message_cart_enable + + + 1 + + Magento\Braintree\Model\Adminhtml\Source\DisabledFundingOptions @@ -512,7 +526,20 @@ Magento\Config\Block\System\Config\Form\Fieldset - + + + Magento\Config\Model\Config\Source\Yesno + payment/braintree_paypal/button_paylater_checkout_enable + + + + Magento\Config\Model\Config\Source\Yesno + payment/braintree_paypal/message_checkout_enable + + + 1 + + Magento\Braintree\Model\Adminhtml\Source\DisabledFundingOptions @@ -558,10 +585,15 @@ Magento\Config\Model\Config\Source\Yesno payment/braintree_paypal/button_productpage_enabled - + + + Magento\Config\Model\Config\Source\Yesno + payment/braintree_paypal/button_paylater_productpage_enable + + Magento\Config\Model\Config\Source\Yesno - payment/braintree_paypal/message_productpage_enabled + payment/braintree_paypal/message_productpage_enable 1 diff --git a/etc/config.xml b/etc/config.xml index bbac72e4..ea1e5f20 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -67,8 +67,13 @@ 2 - 0 - 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 0 diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index ad7f620a..0bd5f5da 100755 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -35,9 +35,6 @@ true - - true - true diff --git a/view/frontend/templates/paypal/button.phtml b/view/frontend/templates/paypal/button.phtml index 96390bde..541f32b1 100644 --- a/view/frontend/templates/paypal/button.phtml +++ b/view/frontend/templates/paypal/button.phtml @@ -23,7 +23,7 @@ try { 'jquery' ], function (button, $) { $(function () { - button.init('getClientToken() ?>'); + button.init('getClientToken() ?>', 'escapeHtmlAttr($block->getCurrency()) ?>'); }) }) @@ -62,22 +62,28 @@ try { isPayLaterActive()): ?> - - isPayLaterMessageActive() && !$block->isPayPalVaultActive()): ?> -
+ isPayLaterButtonActive('cart')):?> + + + isPayLaterMessageActive('cart') && !$block->isPayPalVaultActive()): ?> +
\ No newline at end of file diff --git a/view/frontend/templates/paypal/product_page.phtml b/view/frontend/templates/paypal/product_page.phtml index cce85f59..f05afdf5 100644 --- a/view/frontend/templates/paypal/product_page.phtml +++ b/view/frontend/templates/paypal/product_page.phtml @@ -25,7 +25,7 @@ try { 'jquery' ], function (button, $) { $(function () { - button.init('getClientToken() ?>'); + button.init('getClientToken() ?>', 'escapeHtmlAttr($block->getCurrency()) ?>'); }) }) @@ -66,23 +66,29 @@ try { isPayLaterActive()): ?> - - isPayLaterMessageActive() && !$block->isPayPalVaultActive()): ?> -
+ isPayLaterButtonActive('productpage')):?> + + + isPayLaterMessageActive('productpage') && !$block->isPayPalVaultActive()): ?> +
\ No newline at end of file diff --git a/view/frontend/web/js/paypal/button.js b/view/frontend/web/js/paypal/button.js index 9ae2ace0..adfca77f 100644 --- a/view/frontend/web/js/paypal/button.js +++ b/view/frontend/web/js/paypal/button.js @@ -41,7 +41,7 @@ define( onError: null }, - init: function (token) { + init: function (token, currency) { buttonIds = []; $('.action-braintree-paypal-logo').each(function () { if(!$(this).hasClass( "button-loaded" )) { @@ -51,11 +51,11 @@ define( }); if(buttonIds.length > 0){ - this.loadSDK(token); + this.loadSDK(token, currency); } }, - loadSDK: function (token) { + loadSDK: function (token, currency) { braintree.create({ authorization: token }, function (clientErr, clientInstance) { @@ -76,12 +76,15 @@ define( }, function (err, paypalCheckoutInstance) { if (typeof paypal !== 'undefined' ) { - this.renderpayPalButtons(buttonIds, paypalCheckoutInstance) + this.renderpayPalButtons(buttonIds, paypalCheckoutInstance); + this.renderpayPalMessages(); } else { paypalCheckoutInstance.loadPayPalSDK({ components: 'buttons,messages,funding-eligibility', + currency: currency, }, function () { - this.renderpayPalButtons(buttonIds, paypalCheckoutInstance) + this.renderpayPalButtons(buttonIds, paypalCheckoutInstance); + this.renderpayPalMessages(); }.bind(this)); } @@ -96,6 +99,20 @@ define( }.bind(this)); }, + renderpayPalMessages: function() { + $('.action-braintree-paypal-message').each(function () { + paypal.Messages({ + amount: $(this).data('pp-amount'), + pageType: $(this).data('pp-type'), + style: { + layout: 'text', + } + }).render('#' + $(this).attr('id')); + + + }); + }, + payPalButton: function(id, paypalCheckoutInstance) { let data = $('#' + id); diff --git a/view/frontend/web/js/view/payment/braintree.js b/view/frontend/web/js/view/payment/braintree.js index 13531289..1a354493 100644 --- a/view/frontend/web/js/view/payment/braintree.js +++ b/view/frontend/web/js/view/payment/braintree.js @@ -18,7 +18,6 @@ define( let config = window.checkoutConfig.payment, braintreeType = 'braintree', payPalType = 'braintree_paypal', - payPalCreditType = 'braintree_paypal_credit', braintreeAchDirectDebit = 'braintree_ach_direct_debit'; if (config[braintreeType].isActive) { @@ -39,14 +38,6 @@ define( ); } - if (config[payPalCreditType].isActive) { - rendererList.push( - { - type: payPalCreditType, - component: 'Magento_Braintree/js/view/payment/method-renderer/paypal-credit' - } - ); - } rendererList.push( { @@ -64,13 +55,6 @@ define( ); } - rendererList.push( - { - type: 'braintree_local_payment', - component: 'Magento_Braintree/js/view/payment/method-renderer/lpm' - } - ); - /** Add view logic here if needed */ return Component.extend({}); } diff --git a/view/frontend/web/js/view/payment/method-renderer/paypal-credit.js b/view/frontend/web/js/view/payment/method-renderer/paypal-credit.js deleted file mode 100644 index 8f602139..00000000 --- a/view/frontend/web/js/view/payment/method-renderer/paypal-credit.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright © 2013-2017 Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define([ - 'jquery', - 'underscore', - 'Magento_Braintree/js/view/payment/method-renderer/paypal' -], function ( - $, - _, - Component -) { - 'use strict'; - - return Component.extend({ - defaults: { - template: 'Magento_Braintree/payment/paypal-credit', - code: 'braintree_paypal_credit', - - /** - * PayPal client configuration - * {Object} - */ - clientConfig: { - offerCredit: true, - buttonId: 'braintree_paypal_credit_placeholder' - } - } - }); -}); \ No newline at end of file diff --git a/view/frontend/web/js/view/payment/method-renderer/paypal.js b/view/frontend/web/js/view/payment/method-renderer/paypal.js index 6844107f..4b1f5bd1 100644 --- a/view/frontend/web/js/view/payment/method-renderer/paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/paypal.js @@ -8,6 +8,7 @@ define([ 'jquery', 'underscore', 'Magento_Checkout/js/view/payment/default', + 'braintree', 'braintreeCheckoutPayPalAdapter', 'braintreePayPalCheckout', 'Magento_Checkout/js/model/quote', @@ -17,12 +18,12 @@ define([ 'Magento_Vault/js/view/payment/vault-enabler', 'Magento_Checkout/js/action/create-billing-address', 'Magento_Checkout/js/action/select-billing-address', - 'mage/translate', - 'braintreePayPalInContextCheckout' + 'mage/translate' ], function ( $, _, Component, + braintree, Braintree, paypalCheckout, quote, @@ -65,7 +66,9 @@ define([ paypal: true }, - buttonId: 'braintree_paypal_placeholder', + buttonPayPalId: 'braintree_paypal_placeholder', + buttonCreditId: 'braintree_paypal_credit_placeholder', + buttonPaylaterId: 'braintree_paypal_paylater_placeholder', onDeviceDataRecieved: function (deviceData) { this.additionalData['device_data'] = deviceData; @@ -298,102 +301,101 @@ define([ console.error('paypalCheckout error', createErr); return; } + let quoteObj = quote.totals(); + paypalCheckoutInstance.loadPayPalSDK({ + components: 'buttons,messages,funding-eligibility', + currency: quoteObj['base_currency_code'], + }, function () { + this.loadPayPalButton(paypalCheckoutInstance, 'paypal'); + if(this.isCreditEnabled()) { + this.loadPayPalButton(paypalCheckoutInstance, 'credit'); + } + if(this.isPaylaterEnabled()) { + this.loadPayPalButton(paypalCheckoutInstance, 'paylater'); + } - var paypalPayment = Braintree.config.paypal, - onPaymentMethodReceived = Braintree.config.onPaymentMethodReceived, - style = { - color: Braintree.getColor(), - shape: Braintree.getShape(), - layout: Braintree.getLayout(), - size: Braintree.getSize() - }, - funding = { - allowed: [], - disallowed: [] - }; - - if (Braintree.getLabel()) { - style.label = Braintree.getLabel(); - } - if (Braintree.getBranding()) { - style.branding = Braintree.getBranding(); - } - if (Braintree.getFundingIcons()) { - style.fundingicons = Braintree.getFundingIcons(); - } + }.bind(this)); + }.bind(this)); + }, - if (Braintree.config.offerCredit === true) { - paypalPayment.offerCredit = true; - style.label = "credit"; - style.color = "darkblue"; - style.layout = "horizontal"; - funding.allowed.push(paypal.FUNDING.CREDIT); - } else { - paypalPayment.offerCredit = false; - funding.disallowed.push(paypal.FUNDING.CREDIT); - } + loadPayPalButton: function (paypalCheckoutInstance, funding) { + var paypalPayment = Braintree.config.paypal, + onPaymentMethodReceived = Braintree.config.onPaymentMethodReceived, + style = { + color: Braintree.getColor(), + shape: Braintree.getShape(), + layout: Braintree.getLayout(), + size: Braintree.getSize() + }; + + if (Braintree.getBranding()) { + style.branding = Braintree.getBranding(); + } + if (Braintree.getFundingIcons()) { + style.fundingicons = Braintree.getFundingIcons(); + } - // Disabled function options - var disabledFunding = Braintree.getDisabledFunding(); - if (true === disabledFunding.card) { - funding.disallowed.push(paypal.FUNDING.CARD); - } - if (true === disabledFunding.elv) { - funding.disallowed.push(paypal.FUNDING.ELV); - } + if (funding == 'credit') { + style.layout = "horizontal"; + style.color = "darkblue"; + Braintree.config.buttonId = this.clientConfig.buttonCreditId; + } else if (funding == 'paylater') { + style.layout = "horizontal"; + style.color = "white"; + Braintree.config.buttonId = this.clientConfig.buttonPaylaterId; + } else { + Braintree.config.buttonId = this.clientConfig.buttonPayPalId; + } + // Render + Braintree.config.paypalInstance = paypalCheckoutInstance; + var events = Braintree.events; + $('#' + Braintree.config.buttonId).html(''); + + var button = paypal.Buttons({ + fundingSource: funding, + env: Braintree.getEnvironment(), + style: style, + commit: true, + locale: Braintree.config.paypal.locale, + + createOrder: function () { + return paypalCheckoutInstance.createPayment(paypalPayment); + }, + + onCancel: function (data) { + console.log('checkout.js payment cancelled', JSON.stringify(data, 0, 2)); - // Render - Braintree.config.paypalInstance = paypalCheckoutInstance; - var events = Braintree.events; - - $('#' + Braintree.config.buttonId).html(''); - paypal.Button.render({ - env: Braintree.getEnvironment(), - style: style, - commit: true, - funding: funding, - locale: Braintree.config.paypal.locale, - - payment: function () { - return paypalCheckoutInstance.createPayment(paypalPayment); - }, - - onCancel: function (data) { - console.log('checkout.js payment cancelled', JSON.stringify(data, 0, 2)); - - if (typeof events.onCancel === 'function') { - events.onCancel(); - } - }, - - onError: function (err) { - Braintree.showError($t("PayPal Checkout could not be initialized. Please contact the store owner.")); - Braintree.config.paypalInstance = null; - console.error('Paypal checkout.js error', err); - - if (typeof events.onError === 'function') { - events.onError(err); - } - }.bind(this), - - onClick: function(data) { - if (typeof events.onClick === 'function') { - events.onClick(data); - } - }, - - /** - * Pass the payload (and payload.nonce) through to the implementation's onPaymentMethodReceived method - * @param data - * @param actions - */ - onAuthorize: function (data, actions) { - return paypalCheckoutInstance.tokenizePayment(data) - .then(function (payload) { - onPaymentMethodReceived(payload); - }); + if (typeof events.onCancel === 'function') { + events.onCancel(); } - }, '#' + Braintree.config.buttonId).then(function () { + }, + + onError: function (err) { + Braintree.showError($t("PayPal Checkout could not be initialized. Please contact the store owner.")); + Braintree.config.paypalInstance = null; + console.error('Paypal checkout.js error', err); + + if (typeof events.onError === 'function') { + events.onError(err); + } + }.bind(this), + + onClick: function(data) { + if (typeof events.onClick === 'function') { + events.onClick(data); + } + }, + + onApprove: function (data, actions) { + return paypalCheckoutInstance.tokenizePayment(data) + .then(function (payload) { + onPaymentMethodReceived(payload); + }); + } + + }); + if (button.isEligible()) { + button.render('#' + Braintree.config.buttonId).then(function () { Braintree.enableButton(); if (typeof Braintree.config.onPaymentMethodError === 'function') { Braintree.config.onPaymentMethodError(); @@ -403,7 +405,7 @@ define([ events.onRender(data); } }); - }.bind(this)); + } }, /** @@ -577,9 +579,42 @@ define([ * Get button id * @returns {String} */ - getButtonId: function () { - return this.clientConfig.buttonId; - } + getPayPalButtonId: function () { + return this.clientConfig.buttonPayPalId; + }, + + /** + * Get button id + * @returns {String} + */ + getCreditButtonId: function () { + return this.clientConfig.buttonCreditId; + }, + + /** + * Get button id + * @returns {String} + */ + getPaylaterButtonId: function () { + return this.clientConfig.buttonPaylaterId; + }, + + isPaylaterEnabled: function () { + return window.checkoutConfig.payment['braintree_paypal_paylater']['isActive']; + }, + + isPaylaterMessageEnabled: function () { + return window.checkoutConfig.payment['braintree_paypal_paylater']['isMessageActive']; + }, + + getGrandTotalAmount: function() { + return parseFloat(this.grandTotalAmount).toFixed(2); + }, + + isCreditEnabled: function () { + return window.checkoutConfig.payment['braintree_paypal_credit']['isActive']; + }, + }); }); diff --git a/view/frontend/web/template/payment/paypal-credit.html b/view/frontend/web/template/payment/paypal-credit.html deleted file mode 100644 index ec4fef75..00000000 --- a/view/frontend/web/template/payment/paypal-credit.html +++ /dev/null @@ -1,55 +0,0 @@ - -
-
- - -
- -
- -
-
-
-
- -
-
-
- - - -
- -
- -
-
-
-
-
-
-
- diff --git a/view/frontend/web/template/payment/paypal.html b/view/frontend/web/template/payment/paypal.html index d75813ee..0d1c52f2 100644 --- a/view/frontend/web/template/payment/paypal.html +++ b/view/frontend/web/template/payment/paypal.html @@ -70,8 +70,18 @@
-
+
+ +
+ + +
+ + +
+
- - + \ No newline at end of file From 4f168ff3bf6f0d7ef6420d25ec8c452b4a9ce723 Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Thu, 7 Jan 2021 10:53:57 +0530 Subject: [PATCH 25/37] [PBSD-102] Fixed issue of product name when it is having special characters or other language characters. --- .../Request/Level23ProcessingDataBuilder.php | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Gateway/Request/Level23ProcessingDataBuilder.php b/Gateway/Request/Level23ProcessingDataBuilder.php index d7dd7b82..57c40038 100644 --- a/Gateway/Request/Level23ProcessingDataBuilder.php +++ b/Gateway/Request/Level23ProcessingDataBuilder.php @@ -15,6 +15,7 @@ /** * Class Level23ProcessingDataBuilder + * @package Magento\Braintree\Gateway\Request */ class Level23ProcessingDataBuilder implements BuilderInterface { @@ -43,10 +44,12 @@ class Level23ProcessingDataBuilder implements BuilderInterface * @var SubjectReader */ private $subjectReader; + /** * @var ScopeConfigInterface */ private $scopeConfig; + /** * @var ISO3166 */ @@ -94,30 +97,31 @@ public function build(array $buildSubject): array foreach ($order->getItems() as $item) { // Skip configurable parent items and items with a base price of 0. - if ($item->getParentItem() || 0.0 === $item->getPrice()) { + if ($item->getParentItem() || 0.0 === (float) $item->getPrice()) { continue; } // Regex to replace all unsupported characters. $filteredFields = preg_replace( - '/[^a-zA-Z0-9\s\-.\']/', + '/[^\p{M}\w\s\-.\']/u', '', [ - 'name' => substr($item->getName(), 0, 35), + 'name' => mb_substr($item->getName(), 0, 35), 'unit_of_measure' => substr($item->getProductType(), 0, 12), 'sku' => substr($item->getSku(), 0, 12) ] ); + $itemPrice = (float) $item->getPrice(); $lineItems[] = array_combine( self::LINE_ITEMS_ARRAY, [ $filteredFields['name'], TransactionLineItem::DEBIT, $this->numberToString($item->getQtyOrdered(), 2), - $this->numberToString($item->getBasePrice(), 2), + $this->numberToString($itemPrice, 2), $filteredFields['unit_of_measure'], - $this->numberToString($item->getQtyOrdered() * $item->getBasePrice(), 2), + $this->numberToString($item->getQtyOrdered() * $itemPrice, 2), $item->getTaxAmount() === null ? '0.00' : $this->numberToString($item->getTaxAmount(), 2), $item->getDiscountAmount() === null ? '0.00' : $this->numberToString($item->getDiscountAmount(), 2), $filteredFields['sku'], @@ -155,12 +159,17 @@ public function build(array $buildSubject): array } /** - * @param float $num + * @param $num * @param int $precision * @return string */ - private function numberToString(float $num, int $precision): string + private function numberToString($num, int $precision): string { + // To counter the fact that Magento often wrongly returns a string for price values, we can cast it to a float. + if (is_string($num)) { + $num = (float) $num; + } + return (string) round($num, $precision); } } From 232f7e6ab0196aa64c3f7a4e8bf2390c437d41ab Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Thu, 7 Jan 2021 13:06:00 +0530 Subject: [PATCH 26/37] Fixed LPM TypeError: explode() expects parameter 2 to be string, null given error --- Model/Lpm/Config.php | 28 +++++++++++++++++++--------- etc/adminhtml/system.xml | 12 ++++++------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Model/Lpm/Config.php b/Model/Lpm/Config.php index be2df4f9..848e2a6d 100644 --- a/Model/Lpm/Config.php +++ b/Model/Lpm/Config.php @@ -13,9 +13,10 @@ use Magento\Framework\View\Asset\Repository; /** - * Class Config - * * Provide configuration for LPMs + * + * Class Config + * @package Magento\Braintree\Model\Lpm */ class Config extends \Magento\Payment\Gateway\Config\Config { @@ -81,8 +82,14 @@ class Config extends \Magento\Payment\Gateway\Config\Config private $assetRepo; /** + * Config constructor. + * @param BraintreeAdapter $adapter + * @param BraintreeConfig $braintreeConfig * @param StoreConfigResolver $storeConfigResolver - * {@inheritDoc} + * @param Repository $assetRepo + * @param ScopeConfigInterface $scopeConfig + * @param null $methodCode + * @param $pathPattern */ public function __construct( BraintreeAdapter $adapter, @@ -120,14 +127,17 @@ public function isActive(): bool */ public function getAllowedMethods(): array { - $allowedMethods = explode( - ',', - $this->getValue( - self::KEY_ALLOWED_METHODS, - $this->storeConfigResolver->getStoreId() - ) + $allowedMethodsValue = $this->getValue( + self::KEY_ALLOWED_METHODS, + $this->storeConfigResolver->getStoreId() ); + if (is_null($allowedMethodsValue)) { + return []; + } + + $allowedMethods = explode(',', $allowedMethodsValue); + foreach ($allowedMethods as $allowedMethod) { $this->allowedMethods[] = [ 'method' => $allowedMethod, diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 171773d0..e7c16e7e 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -172,14 +172,14 @@ Magento\Braintree\Block\Adminhtml\Form\Field\Validation
- + Magento\Config\Block\System\Config\Form\Fieldset payment/braintree_cc_vault/title - + If you don't specify the merchant account to use to process a transaction, Braintree will process it using your default merchant account. payment/braintree/merchant_account_id @@ -349,18 +349,18 @@ - + All payments made with a Local Payment Method will be treated as an "Intent Sale" payment action. Magento\Config\Block\System\Config\Form\Fieldset - + Magento\Config\Model\Config\Source\Yesno payment/braintree_local_payment/active - + payment/braintree_local_payment/title required-entry @@ -368,7 +368,7 @@ 1 - + Any particular payment method will only be visible to customers who's billing address is From 38b8783d697e3ac1701f10f451b146ce2fddf39a Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Fri, 8 Jan 2021 17:45:54 +0530 Subject: [PATCH 27/37] [PBSD-32] Fixed Billing Address from PayPal not getting populated issue. --- Block/Paypal/Button.php | 9 +- Model/Paypal/Helper/QuoteUpdater.php | 44 ++++------ Model/Ui/PayPal/ConfigProvider.php | 9 +- view/frontend/templates/paypal/button.phtml | 3 + .../templates/paypal/product_page.phtml | 3 + view/frontend/web/js/paypal/button.js | 85 +++++++++++++------ .../js/view/payment/method-renderer/paypal.js | 27 ++++-- 7 files changed, 117 insertions(+), 63 deletions(-) diff --git a/Block/Paypal/Button.php b/Block/Paypal/Button.php index 89b5b5ec..197feb6b 100644 --- a/Block/Paypal/Button.php +++ b/Block/Paypal/Button.php @@ -27,7 +27,6 @@ class Button extends Template implements ShortcutInterface { const ALIAS_ELEMENT_INDEX = 'alias'; - const BUTTON_ELEMENT_INDEX = 'button_id'; /** @@ -284,4 +283,12 @@ public function getExtraClassname(): string { return $this->getIsCart() ? 'cart' : 'minicart'; } + + /** + * @return bool + */ + public function isRequiredBillingAddress(): bool + { + return (bool) $this->config->isRequiredBillingAddress(); + } } diff --git a/Model/Paypal/Helper/QuoteUpdater.php b/Model/Paypal/Helper/QuoteUpdater.php index 22d0cc0f..1a3c00f3 100755 --- a/Model/Paypal/Helper/QuoteUpdater.php +++ b/Model/Paypal/Helper/QuoteUpdater.php @@ -19,6 +19,7 @@ /** * Class QuoteUpdater + * @package Magento\Braintree\Model\Paypal\Helper */ class QuoteUpdater extends AbstractHelper { @@ -41,13 +42,14 @@ class QuoteUpdater extends AbstractHelper * @var ResourceConnection */ private $resource; + /** * @var Region */ private $region; /** - * Constructor + * QuoteUpdater constructor. * * @param Config $config * @param CartRepositoryInterface $quoteRepository @@ -72,11 +74,9 @@ public function __construct( /** * Execute operation * - * @param string $nonce + * @param $nonce * @param array $details * @param Quote $quote - * @return void - * @throws InvalidArgumentException * @throws LocalizedException */ public function execute($nonce, array $details, Quote $quote) @@ -96,7 +96,6 @@ public function execute($nonce, array $details, Quote $quote) * * @param Quote $quote * @param array $details - * @return void */ private function updateQuote(Quote $quote, array $details) { @@ -148,7 +147,6 @@ private function cleanUpAddress(Quote $quote) * * @param Quote $quote * @param array $details - * @return void */ private function updateQuoteAddress(Quote $quote, array $details) { @@ -165,13 +163,12 @@ private function updateQuoteAddress(Quote $quote, array $details) * * @param Quote $quote * @param array $details - * @return void */ private function updateShippingAddress(Quote $quote, array $details) { $shippingAddress = $quote->getShippingAddress(); - $shippingAddress->setLastname($details['lastName']); - $shippingAddress->setFirstname($details['firstName']); + $shippingAddress->setFirstname($details['shippingAddress']['recipientFirstName']); + $shippingAddress->setLastname($details['shippingAddress']['recipientLastName']); $shippingAddress->setEmail($details['email']); $shippingAddress->setCollectShippingRates(true); @@ -181,7 +178,7 @@ private function updateShippingAddress(Quote $quote, array $details) // PayPal's address supposes not saving against customer account $shippingAddress->setSaveInAddressBook(false); $shippingAddress->setSameAsBilling(false); - $shippingAddress->unsCustomerAddressId(); + $shippingAddress->setCustomerAddressId(null); } /** @@ -194,22 +191,15 @@ private function updateShippingAddress(Quote $quote, array $details) private function updateBillingAddress(Quote $quote, array $details) { $billingAddress = $quote->getBillingAddress(); - $billingAddress->setFirstname($details['firstName']); - $billingAddress->setLastname($details['lastName']); + $billingAddress->setFirstname($details['shippingAddress']['recipientFirstName']); + $billingAddress->setLastname($details['shippingAddress']['recipientLastName']); $billingAddress->setEmail($details['email']); - if ($this->config->isRequiredBillingAddress()) { - $this->updateAddressData($billingAddress, $details['billingAddress']); + if ($this->config->isRequiredBillingAddress() && !empty($details['billingAddress'])) { + $billingAddress->setFirstname($details['firstName']); + $billingAddress->setLastname($details['lastName']); - if (!empty($details['billingAddress']['firstName'])) { - $billingAddress->setFirstname($details['firstName']); - } - if (!empty($details['billingAddress']['lastName'])) { - $billingAddress->setLastname($details['lastName']); - } - if (!empty($details['billingAddress']['email'])) { - $billingAddress->setEmail($details['email']); - } + $this->updateAddressData($billingAddress, $details['billingAddress']); } else { $this->updateAddressData($billingAddress, $details['shippingAddress']); } @@ -217,7 +207,7 @@ private function updateBillingAddress(Quote $quote, array $details) // PayPal's address supposes not saving against customer account $billingAddress->setSaveInAddressBook(false); $billingAddress->setSameAsBilling(false); - $billingAddress->unsCustomerAddressId(); + $billingAddress->setCustomerAddressId(null); } /** @@ -225,7 +215,6 @@ private function updateBillingAddress(Quote $quote, array $details) * * @param Address $address * @param array $addressData - * @return void */ private function updateAddressData(Address $address, array $addressData) { @@ -243,9 +232,12 @@ private function updateAddressData(Address $address, array $addressData) $address->setCountryId($addressData['countryCodeAlpha2']); $address->setPostcode($addressData['postalCode']); + if (!empty($addressData['telephone'])) { + $address->setTelephone($addressData['telephone']); + } + // PayPal's address supposes not saving against customer account $address->setSaveInAddressBook(false); $address->setSameAsBilling(false); - $address->setCustomerAddressId(null); } } diff --git a/Model/Ui/PayPal/ConfigProvider.php b/Model/Ui/PayPal/ConfigProvider.php index 9fc1543f..40e6ea57 100644 --- a/Model/Ui/PayPal/ConfigProvider.php +++ b/Model/Ui/PayPal/ConfigProvider.php @@ -84,7 +84,8 @@ public function getConfig(): array 'shape' => $this->config->getButtonShape(Config::BUTTON_AREA_CHECKOUT), 'size' => $this->config->getButtonSize(Config::BUTTON_AREA_CHECKOUT), 'color' => $this->config->getButtonColor(Config::BUTTON_AREA_CHECKOUT) - ] + ], + 'isRequiredBillingAddress' => $this->config->isRequiredBillingAddress() ], self::PAYPAL_CREDIT_CODE => [ @@ -100,7 +101,8 @@ public function getConfig(): array 'shape' => $this->config->getButtonShape(Config::BUTTON_AREA_CHECKOUT), 'size' => $this->config->getButtonSize(Config::BUTTON_AREA_CHECKOUT), 'color' => $this->config->getButtonColor(Config::BUTTON_AREA_CHECKOUT) - ] + ], + 'isRequiredBillingAddress' => $this->config->isRequiredBillingAddress() ], self::PAYPAL_PAYLATER_CODE => [ @@ -117,7 +119,8 @@ public function getConfig(): array 'shape' => $this->config->getButtonShape(Config::BUTTON_AREA_CHECKOUT), 'size' => $this->config->getButtonSize(Config::BUTTON_AREA_CHECKOUT), 'color' => $this->config->getButtonColor(Config::BUTTON_AREA_CHECKOUT) - ] + ], + 'isRequiredBillingAddress' => $this->config->isRequiredBillingAddress() ] ] ]; diff --git a/view/frontend/templates/paypal/button.phtml b/view/frontend/templates/paypal/button.phtml index 541f32b1..ede3c90d 100644 --- a/view/frontend/templates/paypal/button.phtml +++ b/view/frontend/templates/paypal/button.phtml @@ -41,6 +41,7 @@ try { data-shape="getButtonShape() ?>" data-size="getButtonSize() ?>" data-color="getButtonColor() ?>" + data-requiredbillingaddress="isRequiredBillingAddress() ?>" class="action-braintree-paypal-logo"> @@ -58,6 +59,7 @@ try { data-shape="getButtonShape() ?>" data-size="getButtonSize() ?>" data-color="darkblue" + data-requiredbillingaddress="isRequiredBillingAddress() ?>" class="action-braintree-paypal-logo"> @@ -76,6 +78,7 @@ try { data-shape="getButtonShape() ?>" data-size="getButtonSize() ?>" data-color="white" + data-requiredbillingaddress="isRequiredBillingAddress() ?>" class="action-braintree-paypal-logo"> diff --git a/view/frontend/templates/paypal/product_page.phtml b/view/frontend/templates/paypal/product_page.phtml index f05afdf5..fdd152dc 100644 --- a/view/frontend/templates/paypal/product_page.phtml +++ b/view/frontend/templates/paypal/product_page.phtml @@ -44,6 +44,7 @@ try { data-size="getButtonSize() ?>" data-color="getButtonColor() ?>" data-location="getLocation() ?>" + data-requiredbillingaddress="isRequiredBillingAddress() ?>" class="action-braintree-paypal-logo"> @@ -62,6 +63,7 @@ try { data-size="getButtonSize() ?>" data-color="darkblue" data-location="getLocation() ?>" + data-requiredbillingaddress="isRequiredBillingAddress() ?>" class="action-braintree-paypal-logo"> @@ -81,6 +83,7 @@ try { data-size="getButtonSize() ?>" data-color="white" data-location="getLocation() ?>" + data-requiredbillingaddress="isRequiredBillingAddress() ?>" class="action-braintree-paypal-logo"> diff --git a/view/frontend/web/js/paypal/button.js b/view/frontend/web/js/paypal/button.js index adfca77f..4ee712ba 100644 --- a/view/frontend/web/js/paypal/button.js +++ b/view/frontend/web/js/paypal/button.js @@ -33,7 +33,6 @@ define( 'use strict'; let buttonIds = []; - return { events: { onClick: null, @@ -41,6 +40,10 @@ define( onError: null }, + /** + * @param token + * @param currency + */ init: function (token, currency) { buttonIds = []; $('.action-braintree-paypal-logo').each(function () { @@ -55,6 +58,12 @@ define( } }, + /** + * Load Braintree PayPal SDK + * + * @param token + * @param currency + */ loadSDK: function (token, currency) { braintree.create({ authorization: token @@ -76,15 +85,15 @@ define( }, function (err, paypalCheckoutInstance) { if (typeof paypal !== 'undefined' ) { - this.renderpayPalButtons(buttonIds, paypalCheckoutInstance); - this.renderpayPalMessages(); + this.renderPayPalButtons(buttonIds, paypalCheckoutInstance); + this.renderPayPalMessages(); } else { paypalCheckoutInstance.loadPayPalSDK({ components: 'buttons,messages,funding-eligibility', currency: currency, }, function () { - this.renderpayPalButtons(buttonIds, paypalCheckoutInstance); - this.renderpayPalMessages(); + this.renderPayPalButtons(buttonIds, paypalCheckoutInstance); + this.renderPayPalMessages(); }.bind(this)); } @@ -92,14 +101,24 @@ define( }.bind(this)); }.bind(this)); }, - renderpayPalButtons: function(ids, paypalCheckoutInstance) { + + /** + * Render PayPal buttons + * + * @param ids + * @param paypalCheckoutInstance + */ + renderPayPalButtons: function(ids, paypalCheckoutInstance) { _.each(ids,function(id) { this.payPalButton(id, paypalCheckoutInstance); }.bind(this)); }, - renderpayPalMessages: function() { + /** + * Render PayPal messages + */ + renderPayPalMessages: function() { $('.action-braintree-paypal-message').each(function () { paypal.Messages({ amount: $(this).data('pp-amount'), @@ -113,8 +132,11 @@ define( }); }, + /** + * @param id + * @param paypalCheckoutInstance + */ payPalButton: function(id, paypalCheckoutInstance) { - let data = $('#' + id); let style = { color: data.data('color'), @@ -142,11 +164,13 @@ define( displayName: data.data('displayname') }); }, + validate: function(actions) { var cart = customerData.get('cart'), customer = customerData.get('customer'), declinePayment = false, isGuestCheckoutAllowed; + isGuestCheckoutAllowed = cart().isGuestCheckoutAllowed; declinePayment = !customer().firstname && !isGuestCheckoutAllowed; if (declinePayment) { @@ -157,37 +181,24 @@ define( onCancel: function (data) { jQuery("#maincontent").trigger('processStop'); - - /*if (typeof events.onCancel === 'function') { - events.onCancel(); - }*/ }, onError: function (err) { console.error('paypalCheckout button render error', err); jQuery("#maincontent").trigger('processStop'); - - - /*if (typeof events.onError === 'function') { - events.onError(err); - }*/ }, onClick: function(data) { - var cart = customerData.get('cart'), customer = customerData.get('customer'), declinePayment = false, isGuestCheckoutAllowed; + isGuestCheckoutAllowed = cart().isGuestCheckoutAllowed; declinePayment = !customer().firstname && !isGuestCheckoutAllowed && (typeof isGuestCheckoutAllowed !== 'undefined'); if (declinePayment) { alert($t('To check out, please sign in with your email address.')); } - - /*if (typeof events.onClick === 'function') { - events.onClick(data); - }*/ }, onApprove: function (data1) { @@ -202,13 +213,33 @@ define( locality: address.city.replace(/'/g, "'"), postalCode: address.postalCode, countryCodeAlpha2: address.countryCode, - email: payload.details.email.replace(/'/g, "'"), - firstname: recipientName[0].replace(/'/g, "'"), - lastname: recipientName[1].replace(/'/g, "'"), + recipientFirstName: recipientName[0].replace(/'/g, "'"), + recipientLastName: recipientName[1].replace(/'/g, "'"), telephone: typeof payload.details.phone !== 'undefined' ? payload.details.phone : '', region: typeof address.state !== 'undefined' ? address.state.replace(/'/g, "'") : '' }; - if(data.data('location') == 'productpage') { + payload.details.email = payload.details.email.replace(/'/g, "'"); + payload.details.firstName = payload.details.firstName.replace(/'/g, "'"); + payload.details.lastName = payload.details.lastName.replace(/'/g, "'"); + if (typeof payload.details.businessName !== 'undefined') { + payload.details.businessName = payload.details.businessName.replace(/'/g, "'"); + } + + // Map the billing address correctly + let isRequiredBillingAddress = data.data('requiredbillingaddress'); + if (isRequiredBillingAddress === 1) { + var billingAddress = payload.details.billingAddress; + payload.details.billingAddress = { + streetAddress: typeof billingAddress.line2 !== 'undefined' ? billingAddress.line1.replace(/'/g, "'") + " " + billingAddress.line2.replace(/'/g, "'") : billingAddress.line1.replace(/'/g, "'"), + locality: billingAddress.city.replace(/'/g, "'"), + postalCode: billingAddress.postalCode, + countryCodeAlpha2: billingAddress.countryCode, + telephone: typeof payload.details.phone !== 'undefined' ? payload.details.phone : '', + region: typeof billingAddress.state !== 'undefined' ? billingAddress.state.replace(/'/g, "'") : '' + }; + } + + if(data.data('location') === 'productpage') { var form = $("#product_addtocart_form"); if (!(form.validation() && form.validation('isValid'))) { return false; @@ -236,4 +267,4 @@ define( }, } } -); \ No newline at end of file +); diff --git a/view/frontend/web/js/view/payment/method-renderer/paypal.js b/view/frontend/web/js/view/payment/method-renderer/paypal.js index 4b1f5bd1..c18c45d6 100644 --- a/view/frontend/web/js/view/payment/method-renderer/paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/paypal.js @@ -246,10 +246,18 @@ define([ if (quote.isVirtual()) { this.isReviewRequired(true); } else { - if (quote.shippingAddress() === quote.billingAddress()) { - selectBillingAddress(quote.shippingAddress()); + if (this.isRequiredBillingAddress() === '1' || quote.billingAddress() === null) { + if (typeof data.details.billingAddress !== 'undefined') { + this.setBillingAddress(data.details, data.details.billingAddress); + } else { + this.setBillingAddress(data.details, data.details.shippingAddress); + } } else { - selectBillingAddress(quote.billingAddress()); + if (quote.shippingAddress() === quote.billingAddress()) { + selectBillingAddress(quote.shippingAddress()); + } else { + selectBillingAddress(quote.billingAddress()); + } } this.placeOrder(); @@ -335,11 +343,11 @@ define([ style.fundingicons = Braintree.getFundingIcons(); } - if (funding == 'credit') { + if (funding === 'credit') { style.layout = "horizontal"; style.color = "darkblue"; Braintree.config.buttonId = this.clientConfig.buttonCreditId; - } else if (funding == 'paylater') { + } else if (funding === 'paylater') { style.layout = "horizontal"; style.color = "white"; Braintree.config.buttonId = this.clientConfig.buttonPaylaterId; @@ -416,6 +424,14 @@ define([ return window.checkoutConfig.payment[this.getCode()].locale; }, + /** + * Is Billing Address required from PayPal side + * @returns {exports.isRequiredBillingAddress|(function())|boolean} + */ + isRequiredBillingAddress: function () { + return window.checkoutConfig.payment[this.getCode()].isRequiredBillingAddress; + }, + /** * Get configuration for PayPal * @returns {Object} @@ -617,4 +633,3 @@ define([ }); }); - From 1e57f060b0f8c914af8d5444b93c948de50ae523 Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Fri, 8 Jan 2021 22:16:06 +0530 Subject: [PATCH 28/37] [PBSD-88] Fixed PayPal Button error when order or product total is ZERO --- view/frontend/templates/paypal/button.phtml | 63 +++++++++--------- .../templates/paypal/product_page.phtml | 65 ++++++++++--------- 2 files changed, 65 insertions(+), 63 deletions(-) diff --git a/view/frontend/templates/paypal/button.phtml b/view/frontend/templates/paypal/button.phtml index ede3c90d..504625a2 100644 --- a/view/frontend/templates/paypal/button.phtml +++ b/view/frontend/templates/paypal/button.phtml @@ -17,6 +17,7 @@ try { $paypalPaylaterId = sprintf('paypalpaylater-%s', $block->getContainerId()); } ?> +getAmount() > 0): ?> + diff --git a/view/frontend/templates/multishipping/form_paypal.phtml b/view/frontend/templates/multishipping/form_paypal.phtml new file mode 100644 index 00000000..ea3eb221 --- /dev/null +++ b/view/frontend/templates/multishipping/form_paypal.phtml @@ -0,0 +1,29 @@ + + + diff --git a/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js b/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js new file mode 100644 index 00000000..1a24e2f8 --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js @@ -0,0 +1,123 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ + +define([ + 'jquery', + 'Magento_Braintree/js/view/payment/method-renderer/hosted-fields', + 'Magento_Braintree/js/validator', + 'Magento_Ui/js/model/messageList', + 'mage/translate', + 'Magento_Checkout/js/model/full-screen-loader', + 'Magento_Checkout/js/action/set-payment-information', + 'Magento_Checkout/js/model/payment/additional-validators', + 'Magento_Braintree/js/view/payment/adapter' +], function ( + $, + Component, + validator, + messageList, + $t, + fullScreenLoader, + setPaymentInformationAction, + additionalValidators, + braintree +) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_Braintree/payment/multishipping/form' + }, + + /** + * Get list of available CC types + * + * @returns {Object} + */ + getCcAvailableTypes: function () { + var availableTypes = validator.getAvailableCardTypes(), + billingCountryId; + + billingCountryId = $('#multishipping_billing_country_id').val(); + + if (billingCountryId && validator.getCountrySpecificCardTypes(billingCountryId)) { + return validator.collectTypes( + availableTypes, validator.getCountrySpecificCardTypes(billingCountryId) + ); + } + + return availableTypes; + }, + + /** + * @override + */ + handleNonce: function (data) { + var self = this; + this.setPaymentMethodNonce(data.nonce); + + // place order on success validation + self.validatorManager.validate(self, function () { + return self.setPaymentInformation(); + }, function() { + self.isProcessing = false; + self.paymentMethodNonce = null; + }); + }, + + /** + * @override + */ + placeOrder: function () { + var self = this; + + if (this.isProcessing) { + return false; + } else { + this.isProcessing = true; + } + + braintree.tokenizeHostedFields(); + return false; + }, + + /** + * @override + */ + setPaymentInformation: function () { + if (additionalValidators.validate()) { + fullScreenLoader.startLoader(); + $.when( + setPaymentInformationAction( + this.messageContainer, + this.getData() + ) + ).done(this.done.bind(this)) + .fail(this.fail.bind(this)); + } + }, + + /** + * {Function} + */ + fail: function () { + fullScreenLoader.stopLoader(); + + return this; + }, + + /** + * {Function} + */ + done: function () { + fullScreenLoader.stopLoader(); + $('#multishipping-billing-form').submit(); + + return this; + } + }); +}); diff --git a/view/frontend/web/js/view/payment/method-renderer/multishipping/paypal.js b/view/frontend/web/js/view/payment/method-renderer/multishipping/paypal.js new file mode 100644 index 00000000..9da3d10a --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/multishipping/paypal.js @@ -0,0 +1,226 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define([ + 'jquery', + 'underscore', + 'braintreeCheckoutPayPalAdapter', + 'Magento_Checkout/js/model/quote', + 'Magento_Braintree/js/view/payment/method-renderer/paypal', + 'Magento_Checkout/js/action/set-payment-information', + 'Magento_Checkout/js/model/payment/additional-validators', + 'Magento_Checkout/js/model/full-screen-loader', + 'mage/translate' +], function ( + $, + _, + Braintree, + quote, + Component, + setPaymentInformationAction, + additionalValidators, + fullScreenLoader, + $t +) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_Braintree/payment/multishipping/paypal', + submitButtonSelector: '[id="parent-payment-continue"]', + reviewButtonHtml: '' + }, + + /** + * @override + */ + initObservable: function () { + this.reviewButtonHtml = $(this.submitButtonSelector).html(); + return this._super(); + }, + + initClientConfig: function () { + this.clientConfig = _.extend(this.clientConfig, this.getPayPalConfig()); + this.clientConfig.paypal.enableShippingAddress = false; + + _.each(this.clientConfig, function (fn, name) { + if (typeof fn === 'function') { + this.clientConfig[name] = fn.bind(this); + } + }, this); + this.clientConfig.buttonPayPalId = 'parent-payment-continue'; + + }, + + /** + * @override + */ + onActiveChange: function (isActive) { + this.updateSubmitButtonHtml(isActive); + this._super(isActive); + }, + + /** + * @override + */ + beforePlaceOrder: function (data) { + this._super(data); + }, + + /** + * Re-init PayPal Auth Flow + */ + reInitPayPal: function () { + this.disableButton(); + this.clientConfig.paypal.amount = parseFloat(this.grandTotalAmount).toFixed(2); + + if (!quote.isVirtual()) { + this.clientConfig.paypal.enableShippingAddress = false; + this.clientConfig.paypal.shippingAddressEditable = false; + } + + Braintree.setConfig(this.clientConfig); + + if (Braintree.getPayPalInstance()) { + Braintree.getPayPalInstance().teardown(function () { + Braintree.setup(); + }.bind(this)); + Braintree.setPayPalInstance(null); + } else { + Braintree.setup(); + this.enableButton(); + } + }, + + /** + * Get configuration for PayPal + * @returns {Object} + */ + getPayPalConfig: function () { + var totals = quote.totals(), + config = {}, + isActiveVaultEnabler = this.isActiveVault(); + + config.paypal = { + flow: 'checkout', + amount: parseFloat(this.grandTotalAmount).toFixed(2), + currency: totals['base_currency_code'], + locale: this.getLocale(), + requestBillingAgreement: true, + + /** + * Triggers on any Braintree error + */ + onError: function () { + this.paymentMethodNonce = null; + }, + + /** + * Triggers if browser doesn't support PayPal Checkout + */ + onUnsupported: function () { + this.paymentMethodNonce = null; + } + }; + + if (!quote.isVirtual()) { + config.paypal.enableShippingAddress = false; + config.paypal.shippingAddressEditable = false; + } + + if (this.getMerchantName()) { + config.paypal.displayName = this.getMerchantName(); + } + + return config; + }, + + /** + * @override + */ + getData: function () { + var data = this._super(); + + data['additional_data']['is_active_payment_token_enabler'] = true; + + return data; + }, + + /** + * @override + */ + isActiveVault: function () { + return true; + }, + + /** + * Skipping order review step on checkout with multiple addresses is not allowed. + * + * @returns {Boolean} + */ + isSkipOrderReview: function () { + return false; + }, + + /** + * Checks if payment method nonce is already received. + * + * @returns {Boolean} + */ + isPaymentMethodNonceReceived: function () { + return this.paymentMethodNonce !== null; + }, + + /** + * Update submit button on multi-addresses checkout billing form. + * + * @param {Boolean} isActive + */ + updateSubmitButtonHtml: function (isActive) { + if (this.isPaymentMethodNonceReceived() || !isActive) { + $(this.submitButtonSelector).html(this.reviewButtonHtml); + } + }, + + /** + * @override + */ + placeOrder: function () { + if (!this.isPaymentMethodNonceReceived()) { + this.payWithPayPal(); + } else { + fullScreenLoader.startLoader(); + + $.when( + setPaymentInformationAction( + this.messageContainer, + this.getData() + ) + ).done(this.done.bind(this)) + .fail(this.fail.bind(this)); + } + }, + + /** + * {Function} + */ + fail: function () { + fullScreenLoader.stopLoader(); + + return this; + }, + + /** + * {Function} + */ + done: function () { + fullScreenLoader.stopLoader(); + $('#multishipping-billing-form').submit(); + + return this; + } + }); +}); diff --git a/view/frontend/web/template/payment/multishipping/form.html b/view/frontend/web/template/payment/multishipping/form.html new file mode 100644 index 00000000..348965e6 --- /dev/null +++ b/view/frontend/web/template/payment/multishipping/form.html @@ -0,0 +1,104 @@ + +
+
+
+
+ + + +
+
+ +
+ + + + + + + + +
+
+
+
+
    + +
  • + + + +
  • + +
+ +
+
+ +
+ +
+
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ + + +
+
+
+
+ +
+ +
+ +
+
+ +
+
+
+
\ No newline at end of file diff --git a/view/frontend/web/template/payment/multishipping/paypal.html b/view/frontend/web/template/payment/multishipping/paypal.html new file mode 100644 index 00000000..70944f4e --- /dev/null +++ b/view/frontend/web/template/payment/multishipping/paypal.html @@ -0,0 +1,40 @@ + +
+
+ +
+ +
+ +
+
+
+
+ +
+
+ +
+
+
+
+
\ No newline at end of file From 966568d9b5def13335c281d4304f53932b7ef37b Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Thu, 21 Jan 2021 01:59:17 +0530 Subject: [PATCH 32/37] Fixed PayPal wrong amount issue --- view/frontend/web/js/view/payment/method-renderer/paypal.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/paypal.js b/view/frontend/web/js/view/payment/method-renderer/paypal.js index c18c45d6..687ba4d7 100644 --- a/view/frontend/web/js/view/payment/method-renderer/paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/paypal.js @@ -108,7 +108,7 @@ define([ window.addEventListener('hashchange', function (e) { var methodCode = quote.paymentMethod(); - if (methodCode === 'braintree_paypal' || methodCode === 'braintree_paypal_vault') { + if (methodCode['method'] === 'braintree_paypal' || methodCode['method'] === 'braintree_paypal_vault') { if (e.newURL.indexOf('payment') > 0 && self.grandTotalAmount !== null) { self.reInitPayPal(); } @@ -118,7 +118,7 @@ define([ quote.paymentMethod.subscribe(function (value) { var methodCode = value; - if (methodCode === 'braintree_paypal' || methodCode === 'braintree_paypal_vault') { + if (methodCode['method'] === 'braintree_paypal' || methodCode['method'] === 'braintree_paypal_vault') { self.reInitPayPal(); } }); @@ -136,7 +136,7 @@ define([ self.grandTotalAmount = quote.totals()['base_grand_total']; var methodCode = quote.paymentMethod(); - if (methodCode === 'braintree_paypal' || methodCode === 'braintree_paypal_vault') { + if (methodCode['method'] === 'braintree_paypal' || methodCode['method'] === 'braintree_paypal_vault') { self.reInitPayPal(); } } From d79bf084d960ef0a37757f037823f1cf9e77836a Mon Sep 17 00:00:00 2001 From: Dima Date: Fri, 22 Jan 2021 16:12:46 +0200 Subject: [PATCH 33/37] Paypal not loading on the checkout for Norway --- Model/Ui/PayPal/ConfigProvider.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Model/Ui/PayPal/ConfigProvider.php b/Model/Ui/PayPal/ConfigProvider.php index 40e6ea57..fd960e1a 100644 --- a/Model/Ui/PayPal/ConfigProvider.php +++ b/Model/Ui/PayPal/ConfigProvider.php @@ -68,6 +68,10 @@ public function __construct( */ public function getConfig(): array { + $locale = $this->resolver->getLocale(); + if (in_array($locale, ['nb_NO', 'nn_NO'])) { + $locale = 'no_NO'; + } return [ 'payment' => [ self::PAYPAL_CODE => [ @@ -75,7 +79,7 @@ public function getConfig(): array 'title' => $this->config->getTitle(), 'isAllowShippingAddressOverride' => $this->config->isAllowToEditShippingAddress(), 'merchantName' => $this->config->getMerchantName(), - 'locale' => $this->resolver->getLocale(), + 'locale' => $locale, 'paymentAcceptanceMarkSrc' => 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-medium.png', 'vaultCode' => self::PAYPAL_VAULT_CODE, @@ -93,7 +97,7 @@ public function getConfig(): array 'title' => __('PayPal Credit'), 'isAllowShippingAddressOverride' => $this->config->isAllowToEditShippingAddress(), 'merchantName' => $this->config->getMerchantName(), - 'locale' => $this->resolver->getLocale(), + 'locale' => $locale, 'paymentAcceptanceMarkSrc' => 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/ppc-acceptance-medium.png', 'paymentIcon' => $this->config->getPayPalIcon(), @@ -110,7 +114,7 @@ public function getConfig(): array 'title' => __('PayPal PayLater'), 'isAllowShippingAddressOverride' => $this->config->isAllowToEditShippingAddress(), 'merchantName' => $this->config->getMerchantName(), - 'locale' => $this->resolver->getLocale(), + 'locale' => $locale, 'paymentAcceptanceMarkSrc' => 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/ppc-acceptance-medium.png', 'paymentIcon' => $this->config->getPayPalIcon(), From 82a46c03c222b37dcbd26c1db4061eedf7b42843 Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Mon, 25 Jan 2021 13:40:44 +0530 Subject: [PATCH 34/37] Fixed PayPal DOM element js issue after re-initializing paypal when re-select the method. --- view/frontend/web/js/view/payment/method-renderer/paypal.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/paypal.js b/view/frontend/web/js/view/payment/method-renderer/paypal.js index 687ba4d7..5d6457b5 100644 --- a/view/frontend/web/js/view/payment/method-renderer/paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/paypal.js @@ -47,6 +47,7 @@ define([ grandTotalAmount: null, isReviewRequired: false, customerEmail: null, + methodSelected: false, /** * Additional payment data @@ -118,9 +119,10 @@ define([ quote.paymentMethod.subscribe(function (value) { var methodCode = value; - if (methodCode['method'] === 'braintree_paypal' || methodCode['method'] === 'braintree_paypal_vault') { + if ((methodCode['method'] === 'braintree_paypal' || methodCode['method'] === 'braintree_paypal_vault') && self.methodSelected === false) { self.reInitPayPal(); } + self.methodSelected = false; }); this.vaultEnabler = new VaultEnabler(); @@ -191,6 +193,7 @@ define([ // need always re-init Braintree with PayPal configuration this.reInitPayPal(); + this.methodSelected = true; }, /** From a07661f67cf0f7a439a7e3696403212971d0dffb Mon Sep 17 00:00:00 2001 From: Dima Date: Mon, 25 Jan 2021 15:06:58 +0200 Subject: [PATCH 35/37] Paylater for UK --- etc/adminhtml/system.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index e7c16e7e..cf3ae227 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -42,6 +42,7 @@ 1 + 0
@@ -54,6 +55,8 @@ 1 + 0 + US @@ -509,6 +512,9 @@ Magento\Config\Model\Config\Source\Yesno payment/braintree_paypal/button_paylater_cart_enable + + US + @@ -562,6 +568,9 @@ Magento\Config\Model\Config\Source\Yesno payment/braintree_paypal/button_paylater_checkout_enable + + US + @@ -621,6 +630,9 @@ Magento\Config\Model\Config\Source\Yesno payment/braintree_paypal/button_paylater_productpage_enable + + US + From 3b400ad7169c0ca86b2269384b23c086d6def6ff Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Thu, 28 Jan 2021 18:32:19 +0530 Subject: [PATCH 36/37] Fixed multi-shipping braintree CC payment method issue --- etc/di.xml | 9 --------- etc/frontend/di.xml | 9 +++++++++ .../method-renderer/multishipping/hosted-fields.js | 9 +++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/etc/di.xml b/etc/di.xml index 40bd90ae..a6f589cc 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -1177,13 +1177,4 @@ Magento\Customer\Model\ResourceModel\CustomerRepository\Proxy
- - - - - Magento\Braintree\Model\Multishipping\PlaceOrder - Magento\Braintree\Model\Multishipping\PlaceOrder - - - diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml index ddb334b9..8d3a2d1f 100755 --- a/etc/frontend/di.xml +++ b/etc/frontend/di.xml @@ -104,4 +104,13 @@ + + + + + Magento\Braintree\Model\Multishipping\PlaceOrder + Magento\Braintree\Model\Multishipping\PlaceOrder + + + diff --git a/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js b/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js index 1a24e2f8..444f8126 100644 --- a/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js +++ b/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js @@ -12,7 +12,7 @@ define([ 'Magento_Ui/js/model/messageList', 'mage/translate', 'Magento_Checkout/js/model/full-screen-loader', - 'Magento_Checkout/js/action/set-payment-information', + 'Magento_Checkout/js/action/set-payment-information-extended', 'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Braintree/js/view/payment/adapter' ], function ( @@ -22,7 +22,7 @@ define([ messageList, $t, fullScreenLoader, - setPaymentInformationAction, + setPaymentInformationExtended, additionalValidators, braintree ) { @@ -92,9 +92,10 @@ define([ if (additionalValidators.validate()) { fullScreenLoader.startLoader(); $.when( - setPaymentInformationAction( + setPaymentInformationExtended( this.messageContainer, - this.getData() + this.getData(), + true ) ).done(this.done.bind(this)) .fail(this.fail.bind(this)); From afa4815de416d93e639a2162aea633a25d30bdd9 Mon Sep 17 00:00:00 2001 From: kartikmaniyar Date: Thu, 28 Jan 2021 18:42:15 +0530 Subject: [PATCH 37/37] Upgraded extension to v4.0.6 --- composer.json | 2 +- etc/module.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 3dd7937d..c430d17a 100755 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "gene/module-braintree", "description": "Fork from the Magento Braintree 2.2.0 module by Gene Commerce for PayPal.", - "version": "4.0.5", + "version": "4.0.6", "type": "magento2-module", "license": "proprietary", "require": { diff --git a/etc/module.xml b/etc/module.xml index 0d107ff5..e4f9f6f8 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -6,7 +6,7 @@ */ --> - +