diff --git a/Plugin/Quote/Model/QuoteManagement/DisableFastlaneAddressValidationPlugin.php b/Plugin/Quote/Model/QuoteManagement/DisableBoldAddressValidationPlugin.php similarity index 50% rename from Plugin/Quote/Model/QuoteManagement/DisableFastlaneAddressValidationPlugin.php rename to Plugin/Quote/Model/QuoteManagement/DisableBoldAddressValidationPlugin.php index 66c1bf1..acc4665 100644 --- a/Plugin/Quote/Model/QuoteManagement/DisableFastlaneAddressValidationPlugin.php +++ b/Plugin/Quote/Model/QuoteManagement/DisableBoldAddressValidationPlugin.php @@ -1,4 +1,5 @@ getPayment()->getMethod() !== Service::CODE_FASTLANE) { + if (!in_array($quote->getPayment()->getMethod(), self::BOLD_METHODS_CODES)) { return; } $quote->getBillingAddress()->setShouldIgnoreValidation(true); + $quote->getShippingAddress()->setShouldIgnoreValidation(true); } } diff --git a/etc/csp_whitelist.xml b/etc/csp_whitelist.xml index 7374bb0..e84c52c 100644 --- a/etc/csp_whitelist.xml +++ b/etc/csp_whitelist.xml @@ -59,6 +59,7 @@ static.boldcommerce.com *.paypal.com + www.gstatic.com diff --git a/etc/di.xml b/etc/di.xml index 244b99e..128c085 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -18,7 +18,7 @@ - + diff --git a/view/frontend/requirejs-config.js b/view/frontend/requirejs-config.js index 0944c78..bf43abf 100644 --- a/view/frontend/requirejs-config.js +++ b/view/frontend/requirejs-config.js @@ -10,14 +10,33 @@ let config = { }, }, paths: { + bold_braintree_client: 'https://js.braintreegateway.com/web/3.106.0/js/client.min', + bold_braintree_data_collector: 'https://js.braintreegateway.com/web/3.106.0/js/data-collector.min', + bold_braintree_google_payment: 'https://js.braintreegateway.com/web/3.106.0/js/google-payment.min', + bold_braintree_paypal_checkout: 'https://js.braintreegateway.com/web/3.106.0/js/paypal-checkout.min', + bold_google_pay: 'https://pay.google.com/gp/p/js/pay', + bold_apple_pay: 'https://js.braintreegateway.com/web/3.106.0/js/apple-pay.min', bold_braintree_fastlane_client: 'https://js.braintreegateway.com/web/3.107.1/js/client.min', bold_braintree_fastlane: 'https://js.braintreegateway.com/web/3.107.1/js/fastlane', bold_braintree_fastlane_data_collector: 'https://js.braintreegateway.com/web/3.107.1/js/data-collector.min', bold_braintree_fastlane_hosted_fields: 'https://js.braintreegateway.com/web/3.107.1/js/hosted-fields.min', + bold_ppcp_fastlane_client: 'https://js.braintreegateway.com/web/3.107.1/js/client.min', + bold_ppcp_fastlane_hosted_fields: 'https://js.braintreegateway.com/web/3.107.1/js/hosted-fields.min', 'fastlane/axo': 'https://www.paypalobjects.com/connect-boba/axo', 'fastlane/axo.min': 'https://www.paypalobjects.com/connect-boba/axo.min' }, shim: { + 'bold_braintree_client': { + exports: 'braintree.client' + }, + 'bold_braintree_data_collector': { + deps: ['bold_braintree_client'], + exports: 'braintree.dataCollector' + }, + 'bold_braintree_data_google_payment': { + deps: ['bold_braintree_client'], + exports: 'braintree.googlePayment' + }, 'bold_braintree_fastlane_client': { exports: 'braintree.fastlane_client' }, diff --git a/view/frontend/web/js/action/convert-bold-address.js b/view/frontend/web/js/action/convert-bold-address.js deleted file mode 100644 index b1e95e8..0000000 --- a/view/frontend/web/js/action/convert-bold-address.js +++ /dev/null @@ -1,47 +0,0 @@ -define( - [ - 'Magento_Checkout/js/model/new-customer-address', - 'Magento_Customer/js/customer-data' - ], function ( - NewCustomerAddressModel, - customerData - ) { - 'use strict'; - /** - * Convert bold address to Magento address. - * - * @param {Object} boldAddress - * @return {Object} - */ - return function (boldAddress) { - const directoryData = customerData.get('directory-data'); - const regions = directoryData()[boldAddress.country_code].regions; - let regionId = null; - let regionName = null; - if (regions !== undefined) { - Object.entries(regions).forEach(([key, value]) => { - if (value.code === boldAddress.province_code) { - regionId = key; - regionName = value.name; - } - }); - } - const convertedAddress = { - firstname: boldAddress.first_name, - lastname: boldAddress.last_name, - street: [boldAddress.address_line_1, boldAddress.address_line_2], - city: boldAddress.city, - company: boldAddress.business_name, - region: { - region: regionName, - region_code: boldAddress.region || null, - region_id: regionId - }, - region_id: regionId, - postcode: boldAddress.postal_code, - country_id: boldAddress.country_code, - telephone: boldAddress.phone_number, - }; - return new NewCustomerAddressModel(convertedAddress); - }; - }); diff --git a/view/frontend/web/js/action/create-wallet-pay-order-action.js b/view/frontend/web/js/action/create-wallet-pay-order-action.js deleted file mode 100644 index 3054763..0000000 --- a/view/frontend/web/js/action/create-wallet-pay-order-action.js +++ /dev/null @@ -1,22 +0,0 @@ -define([ - 'Bold_CheckoutPaymentBooster/js/model/platform-client' -], -function ( - platformClient -) { - 'use strict'; - - /** - * Create Wallet Pay order. - */ - return async function (paymentPayload) { - return await platformClient.post( - 'rest/V1/express_pay/order/create', - { - quoteMaskId: window.checkoutConfig.quoteData.entity_id, - gatewayId: paymentPayload.gateway_id, - shippingStrategy: paymentPayload.shipping_strategy || 'dynamic' - } - ); - }; -}); diff --git a/view/frontend/web/js/action/eps-initialize-action.js b/view/frontend/web/js/action/eps-initialize-action.js deleted file mode 100644 index 588542c..0000000 --- a/view/frontend/web/js/action/eps-initialize-action.js +++ /dev/null @@ -1,20 +0,0 @@ -define( - [ - 'Bold_CheckoutPaymentBooster/js/model/eps-client', - ], - function ( - epsClient, - ) { - 'use strict'; - - /** - * Initialize EPS client. - */ - return async function () { - if (!window.checkoutConfig.bold.gatewayId) { - return; - } - const response = await epsClient.get('{{configuration-group-label}}/client_init?option=fastlane') - return response[window.checkoutConfig.bold.gatewayId] || null; - }; - }); diff --git a/view/frontend/web/js/action/convert-magento-address.js b/view/frontend/web/js/action/express-pay/convert-magento-address-action.js similarity index 91% rename from view/frontend/web/js/action/convert-magento-address.js rename to view/frontend/web/js/action/express-pay/convert-magento-address-action.js index e88b2b3..0ddb3e2 100644 --- a/view/frontend/web/js/action/convert-magento-address.js +++ b/view/frontend/web/js/action/express-pay/convert-magento-address-action.js @@ -1,10 +1,8 @@ define( [ - 'Magento_Checkout/js/model/new-customer-address', 'Magento_Customer/js/customer-data', 'checkoutData' ], function ( - NewCustomerAddressModel, customerData, checkoutData ) { @@ -12,7 +10,7 @@ define( /** * Convert Magento address to Bold address. * - * @param {Object} boldAddress + * @param {Object} magentoAddress * @return {Object} */ return function (magentoAddress) { diff --git a/view/frontend/web/js/action/express-pay/create-wallet-pay-order-action.js b/view/frontend/web/js/action/express-pay/create-wallet-pay-order-action.js new file mode 100644 index 0000000..95dc58d --- /dev/null +++ b/view/frontend/web/js/action/express-pay/create-wallet-pay-order-action.js @@ -0,0 +1,26 @@ +define( + [ + 'Bold_CheckoutPaymentBooster/js/model/platform-client' + ], + function ( + platformClient + ) { + 'use strict'; + + /** + * Create Wallet Pay order. + * + * @param {{}} + * @return {Promise} + */ + return async function (paymentPayload) { + return platformClient.post( + 'rest/V1/express_pay/order/create', + { + quoteMaskId: window.checkoutConfig.quoteData.entity_id, + gatewayId: paymentPayload.gateway_id, + shippingStrategy: paymentPayload.shipping_strategy || 'dynamic' + } + ); + }; + }); diff --git a/view/frontend/web/js/action/get-express-pay-order-action.js b/view/frontend/web/js/action/express-pay/get-express-pay-order-action.js similarity index 100% rename from view/frontend/web/js/action/get-express-pay-order-action.js rename to view/frontend/web/js/action/express-pay/get-express-pay-order-action.js diff --git a/view/frontend/web/js/action/express-pay/get-required-order-data-action.js b/view/frontend/web/js/action/express-pay/get-required-order-data-action.js new file mode 100644 index 0000000..f480a8c --- /dev/null +++ b/view/frontend/web/js/action/express-pay/get-required-order-data-action.js @@ -0,0 +1,75 @@ +define( + [ + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/checkout-data', + 'Magento_Checkout/js/model/shipping-service', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/convert-magento-address-action' + ], + function ( + quote, + checkoutData, + shippingService, + convertMagentoAddressAction + ) { + 'use strict'; + + /** + * Get required order data for express pay. + * + * @return {Promise} + */ + return function (requirements) { + const payload = {}; + + for (const requirement of requirements) { + switch (requirement) { + case 'customer': + let billingAddress = quote.billingAddress(); + const email = checkoutData.getValidatedEmailValue() + ? checkoutData.getValidatedEmailValue() + : window.checkoutConfig.customerData.email; + + payload[requirement] = { + first_name: billingAddress.firstname, + last_name: billingAddress.lastname, + email_address: email, + }; + break; + case 'items': + payload[requirement] = quote.getItems().map(item => ({ + amount: parseInt(parseFloat(item.base_price) * 100), + label: item.name + })); + break; + case 'billing_address': + payload[requirement] = convertMagentoAddressAction(quote.billingAddress()); + break; + case 'shipping_address': + payload[requirement] = convertMagentoAddressAction(quote.shippingAddress()); + break; + case 'shipping_options': + payload[requirement] = shippingService.getShippingRates().map(option => ({ + label: `${option.carrier_title} - ${option.method_title}`, + amount: parseFloat(option.amount) * 100, + id: `${option.carrier_code}_${option.method_code}`, + is_selected: option.carrier_code === quote.shippingMethod()?.carrier_code && + option.method_code === quote.shippingMethod()?.method_code + })); + break; + case 'totals': + const totals = quote.getTotals(); + payload[requirement] = { + order_total: parseFloat(totals()['grand_total'] || 0) * 100, + order_balance: parseFloat(totals()['grand_total'] || 0) * 100, + shipping_total: parseFloat(totals()['shipping_amount'] || 0) * 100, + discounts_total: parseFloat(totals()['discount_amount'] || 0) * 100, + fees_total: parseFloat(totals()['fee_amount'] || 0) * 100, + taxes_total: parseFloat(totals()['tax'] || 0) * 100, + }; + break; + } + } + return payload; + }; + } +); diff --git a/view/frontend/web/js/action/payment-sca-action.js b/view/frontend/web/js/action/express-pay/payment-sca-action.js similarity index 100% rename from view/frontend/web/js/action/payment-sca-action.js rename to view/frontend/web/js/action/express-pay/payment-sca-action.js diff --git a/view/frontend/web/js/action/express-pay/save-shipping-information-action.js b/view/frontend/web/js/action/express-pay/save-shipping-information-action.js new file mode 100644 index 0000000..42ba155 --- /dev/null +++ b/view/frontend/web/js/action/express-pay/save-shipping-information-action.js @@ -0,0 +1,45 @@ +define( + [ + 'Magento_Checkout/js/model/quote', + 'mage/storage', + 'Magento_Checkout/js/model/resource-url-manager', + 'Magento_Checkout/js/model/shipping-save-processor/payload-extender', + 'Magento_Checkout/js/model/error-processor' + ], + function ( + quote, + storage, + resourceUrlManager, + payloadExtender, + errorProcessor + ) { + 'use strict'; + + /** + * Save shipping information. + * + * @param {Boolean} saveBillingAddress - Save billing address with shipping information. + * @return {Deferred} + */ + return function (saveBillingAddress = false) { + let payload; + payload = { + addressInformation: { + 'shipping_address': quote.shippingAddress(), + 'shipping_method_code': quote.shippingMethod() ? quote.shippingMethod()['method_code'] : null, + 'shipping_carrier_code': quote.shippingMethod() ? quote.shippingMethod()['carrier_code'] : null, + } + }; + if (saveBillingAddress) { + payload.addressInformation.billing_address = quote.billingAddress(); + } + payloadExtender(payload); + return storage.post( + resourceUrlManager.getUrlForSetShippingInformation(quote), + JSON.stringify(payload) + ).fail((response) => { + errorProcessor.process(response); + }); + } + } +); diff --git a/view/frontend/web/js/action/express-pay/update-quote-address-action.js b/view/frontend/web/js/action/express-pay/update-quote-address-action.js new file mode 100644 index 0000000..b62ade1 --- /dev/null +++ b/view/frontend/web/js/action/express-pay/update-quote-address-action.js @@ -0,0 +1,87 @@ +define( + [ + 'Magento_Checkout/js/model/quote', + 'Magento_Customer/js/customer-data', + 'Magento_Checkout/js/model/address-converter', + ], + function ( + quote, + customerData, + magentoAddressConverter + ) { + 'use strict'; + + /** + * Update quote billing or shipping address action. + * + * @param {String} addressType + * @param {Object} addressData + */ + return function (addressType, addressData) { + const directoryData = customerData.get('directory-data'); + let regions; + const countryCode = addressData['country_code'] || addressData['countryCode']; + try { + regions = directoryData()[countryCode].regions; + } catch (e) { + regions = null; + } + + let regionId = null; + let regionName = null; + const state = addressData['state'] || addressData['administrativeArea']; + if (regions) { + Object.entries(regions).forEach(([key, value]) => { + if (value.code === state || value.name === state) { + regionId = key; + regionName = value.name; + } + }); + } + let firstName = addressData['first_name'] || addressData['givenName'] || null; + let lastName = addressData['last_name'] || addressData['familyName'] || null; + if (!firstName && !lastName) { + const nameParts = (addressData['name'] || '').split(' '); + if (nameParts.length > 1) { + firstName = nameParts[0]; + lastName = nameParts.slice(1).join(' '); + } + } + let street1 = addressData['address1'] || addressData['address_line1'] || addressData['line1']; + let street2 = addressData['address2'] || addressData['address_line2'] || addressData['line2']; + if (addressData['addressLines']) { + street1 = addressData['addressLines'][0] || street1; + street2 = addressData['addressLines'][1] || street2; + } + const region = regionId ? { + region: regionName, + region_code: state, + region_id: regionId + } : regionName; + const quoteAddress = magentoAddressConverter.formAddressDataToQuoteAddress( + { + address_type: addressType, + firstname: firstName, + lastname: lastName, + street: [ + street1 || null, + street2 || null, + ], + city: addressData['city'] || addressData['locality'], + region: region, + region_id: regionId, + telephone: addressData['phoneNumber'] ?? null, + postcode: addressData['postal_code'] || addressData['postalCode'], + country_id: countryCode, + email: addressData['email'] ?? null + } + ); + + if (addressType === 'shipping') { + quote.shippingAddress(quoteAddress); + return; + } + quote.billingAddress(quoteAddress); + } + } +); diff --git a/view/frontend/web/js/action/express-pay/update-quote-braintree-action.js b/view/frontend/web/js/action/express-pay/update-quote-braintree-action.js new file mode 100644 index 0000000..88a969b --- /dev/null +++ b/view/frontend/web/js/action/express-pay/update-quote-braintree-action.js @@ -0,0 +1,55 @@ +define( + [ + 'Magento_Checkout/js/model/quote', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/update-quote-address-action', + ], + function ( + quote, + updateQuoteAddressAction + ) { + 'use strict'; + + /** + * Process braintree order action. + * + * @param {{}} paymentInformation + * @param {{}} paymentApprovalData + * @return {void} + */ + return async function (paymentInformation, paymentApprovalData) { + const paymentData = paymentApprovalData.payment_data; + if (paymentData.email) { + quote.guestEmail = paymentData.email; + paymentData.shipping_address['email'] = paymentData.email; + paymentData.billing_address['email'] = paymentData.email; + } + if (!quote.guestEmail && paymentData.billing_address.email) { + quote.guestEmail = paymentData.billing_address.email; + } + if (!quote.guestEmail && paymentData.shipping_address.email) { + quote.guestEmail = paymentData.shipping_address.email; + } + if (paymentData.customer) { + quote.guestEmail = paymentData.customer.email_address; + if (paymentData.billing_address) { + paymentData.billing_address['email'] = paymentData.customer.email_address; + paymentData.billing_address['first_name'] = paymentData.customer.first_name; + paymentData.billing_address['last_name'] = paymentData.customer.last_name; + paymentData.billing_address['phone'] = paymentData.customer.phone; + } + if (paymentData.shipping_address) { + paymentData.shipping_address['email'] = paymentData.customer.email_address; + paymentData.shipping_address['first_name'] = paymentData.customer.first_name; + paymentData.shipping_address['last_name'] = paymentData.customer.last_name; + paymentData.shipping_address['phone'] = paymentData.customer.phone; + } + } + if (paymentData.shipping_address) { + updateQuoteAddressAction('shipping', paymentData.shipping_address); + } + if (paymentData.billing_address) { + updateQuoteAddressAction('billing', paymentData.billing_address); + } + }; + } +); diff --git a/view/frontend/web/js/action/express-pay/update-quote-ppcp-action.js b/view/frontend/web/js/action/express-pay/update-quote-ppcp-action.js new file mode 100644 index 0000000..101c2e0 --- /dev/null +++ b/view/frontend/web/js/action/express-pay/update-quote-ppcp-action.js @@ -0,0 +1,57 @@ +define( + [ + 'uiRegistry', + 'jquery', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/action/place-order', + 'Magento_Checkout/js/action/redirect-on-success', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/get-express-pay-order-action', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/update-quote-address-action', + ], + function ( + registry, + $, + quote, + placeOrderAction, + redirectOnSuccessAction, + getExpressPayOrderAction, + updateQuoteAddressAction, + ) { + 'use strict'; + + /** + * Place order action. + * + * @return {Promise} + */ + return async function (paymentApprovalData) { + let order; + try { + order = await getExpressPayOrderAction( + paymentApprovalData.gateway_id, + paymentApprovalData.payment_data.order_id + ); + } catch (error) { + console.error('Could not retrieve Express Pay order.', error); + + return; + } + const _convertAddress = function (address, order) { + address.first_name = order.first_name; + address.last_name = order.last_name; + address.state = address.province; + address.country_code = address.country; + address.email = order.email; + + delete address.province; + delete address.country; + + return address; + } + + quote.guestEmail = order.email; + updateQuoteAddressAction('shipping', _convertAddress(order.shipping_address, order)); + updateQuoteAddressAction('billing', _convertAddress(order.billing_address, order)); + }; + } +); diff --git a/view/frontend/web/js/action/express-pay/update-quote-shipping-method-action.js b/view/frontend/web/js/action/express-pay/update-quote-shipping-method-action.js new file mode 100644 index 0000000..a02be30 --- /dev/null +++ b/view/frontend/web/js/action/express-pay/update-quote-shipping-method-action.js @@ -0,0 +1,43 @@ +define( + [ + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/shipping-service', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/save-shipping-information-action' + ], + function ( + quote, + shippingService, + saveShippingInformation + ) { + 'use strict'; + + /** + * Update quote shipping method and save shipping information. + * + * @param {Object} shippingMethod + * @return void + */ + return function (shippingMethod = null) { + let newMethod = null; + if (shippingMethod !== null) { + let availableMethods = shippingService.getShippingRates().filter((method) => { + let methodId = `${method.carrier_code}_${method.method_code}`; + methodId = methodId.replace(/\s/g, ''); + return methodId === shippingMethod['id']; + }); + if (availableMethods.length > 0) { + newMethod = availableMethods[0]; + } + } else { + newMethod = shippingService.getShippingRates().first(); + } + if (newMethod !== null) { + quote.shippingMethod(newMethod); + } + if (quote.guestEmail === null) { + quote.guestEmail = 'test@test.com'; + } + saveShippingInformation(); + } + } +); diff --git a/view/frontend/web/js/action/express-pay/update-wallet-pay-order-action.js b/view/frontend/web/js/action/express-pay/update-wallet-pay-order-action.js new file mode 100644 index 0000000..58fea6e --- /dev/null +++ b/view/frontend/web/js/action/express-pay/update-wallet-pay-order-action.js @@ -0,0 +1,27 @@ +define( + [ + 'Bold_CheckoutPaymentBooster/js/model/platform-client' + ], + function ( + platformClient + ) { + 'use strict'; + + /** + * Update Wallet Pay order. + * + * @param {string} orderId + * @return {Promise} + */ + return async function (orderId) { + // todo: should be put instead of post method. + return platformClient.post( + 'rest/V1/express_pay/order/update', + { + quoteMaskId: window.checkoutConfig.quoteData.entity_id, + gatewayId: window.checkoutConfig.bold.gatewayId, + paypalOrderId: orderId + } + ); + }; + }); diff --git a/view/frontend/web/js/action/convert-fastlane-address.js b/view/frontend/web/js/action/fastlane/convert-fastlane-address-action.js similarity index 100% rename from view/frontend/web/js/action/convert-fastlane-address.js rename to view/frontend/web/js/action/fastlane/convert-fastlane-address-action.js diff --git a/view/frontend/web/js/action/eps-tokenize-action.js b/view/frontend/web/js/action/fastlane/eps-tokenize-action.js similarity index 93% rename from view/frontend/web/js/action/eps-tokenize-action.js rename to view/frontend/web/js/action/fastlane/eps-tokenize-action.js index 5250585..e95ab7e 100644 --- a/view/frontend/web/js/action/eps-tokenize-action.js +++ b/view/frontend/web/js/action/fastlane/eps-tokenize-action.js @@ -4,7 +4,7 @@ define( 'Magento_Checkout/js/model/quote' ], function ( - epsClient, + fastlaneEpsClient, quote ) { 'use strict'; @@ -30,7 +30,7 @@ define( } }; - return await epsClient.post( + return await fastlaneEpsClient.post( path, body, ); diff --git a/view/frontend/web/js/action/hide-shipping-address-form.js b/view/frontend/web/js/action/fastlane/hide-shipping-address-form-action.js similarity index 100% rename from view/frontend/web/js/action/hide-shipping-address-form.js rename to view/frontend/web/js/action/fastlane/hide-shipping-address-form-action.js diff --git a/view/frontend/web/js/action/reset-shipping-address.js b/view/frontend/web/js/action/fastlane/reset-shipping-address-action.js similarity index 88% rename from view/frontend/web/js/action/reset-shipping-address.js rename to view/frontend/web/js/action/fastlane/reset-shipping-address-action.js index f04fe5f..e451d7b 100644 --- a/view/frontend/web/js/action/reset-shipping-address.js +++ b/view/frontend/web/js/action/fastlane/reset-shipping-address-action.js @@ -1,7 +1,7 @@ define( [ 'Magento_Checkout/js/model/quote', - 'Bold_CheckoutPaymentBooster/js/action/show-shipping-address-form' + 'Bold_CheckoutPaymentBooster/js/action/fastlane/show-shipping-address-form-action' ], function ( quote, showShippingAddressForm, diff --git a/view/frontend/web/js/action/set-quote-shipping-address.js b/view/frontend/web/js/action/fastlane/set-quote-shipping-address-action.js similarity index 84% rename from view/frontend/web/js/action/set-quote-shipping-address.js rename to view/frontend/web/js/action/fastlane/set-quote-shipping-address-action.js index d880972..497b6ef 100644 --- a/view/frontend/web/js/action/set-quote-shipping-address.js +++ b/view/frontend/web/js/action/fastlane/set-quote-shipping-address-action.js @@ -1,10 +1,10 @@ define( [ 'checkoutData', - 'Bold_CheckoutPaymentBooster/js/action/convert-fastlane-address', + 'Bold_CheckoutPaymentBooster/js/action/fastlane/convert-fastlane-address-action', 'Magento_Checkout/js/action/select-shipping-address', 'Magento_Checkout/js/action/select-billing-address', - 'Bold_CheckoutPaymentBooster/js/action/hide-shipping-address-form', + 'Bold_CheckoutPaymentBooster/js/action/fastlane/hide-shipping-address-form-action', 'Magento_Checkout/js/model/quote' ], function ( checkoutData, diff --git a/view/frontend/web/js/action/show-fastlane-shipping-address-form.js b/view/frontend/web/js/action/fastlane/show-fastlane-shipping-address-form-action.js similarity index 93% rename from view/frontend/web/js/action/show-fastlane-shipping-address-form.js rename to view/frontend/web/js/action/fastlane/show-fastlane-shipping-address-form-action.js index 6ecdd5a..7a3af47 100644 --- a/view/frontend/web/js/action/show-fastlane-shipping-address-form.js +++ b/view/frontend/web/js/action/fastlane/show-fastlane-shipping-address-form-action.js @@ -1,7 +1,7 @@ define( [ 'Bold_CheckoutPaymentBooster/js/model/spi', - 'Bold_CheckoutPaymentBooster/js/action/set-quote-shipping-address' + 'Bold_CheckoutPaymentBooster/js/action/fastlane/set-quote-shipping-address-action' ], function ( spi, setQuoteShippingAddressAction diff --git a/view/frontend/web/js/action/show-shipping-address-form.js b/view/frontend/web/js/action/fastlane/show-shipping-address-form-action.js similarity index 100% rename from view/frontend/web/js/action/show-shipping-address-form.js rename to view/frontend/web/js/action/fastlane/show-shipping-address-form-action.js diff --git a/view/frontend/web/js/action/hydrate-order-action.js b/view/frontend/web/js/action/general/hydrate-order-action.js similarity index 100% rename from view/frontend/web/js/action/hydrate-order-action.js rename to view/frontend/web/js/action/general/hydrate-order-action.js diff --git a/view/frontend/web/js/action/general/load-script-action.js b/view/frontend/web/js/action/general/load-script-action.js new file mode 100644 index 0000000..3cc4b0b --- /dev/null +++ b/view/frontend/web/js/action/general/load-script-action.js @@ -0,0 +1,35 @@ +define( + [], + function () { + 'use strict'; + /** + * Load given script via require js. + * + * @param {string} type + * @param {string} variable + * @return {Promise} + */ + return function (type, variable = null) { + return new Promise((resolve, reject) => { + require([type], (src) => { + if (!variable) { + resolve(src); + return; + } + const variableParts = variable.split('.'); + let current = window; + for (let i = 0; i < variableParts.length; i++) { + if (!current[variableParts[i]]) { + current[variableParts[i]] = {}; + } + if (i === variableParts.length - 1) { + current[variableParts[i]] = src; + } + current = current[variableParts[i]]; + } + resolve(src); + }, reject); + }); + }; + } +); diff --git a/view/frontend/web/js/action/reload-cart-action.js b/view/frontend/web/js/action/reload-cart-action.js deleted file mode 100644 index 935d3a3..0000000 --- a/view/frontend/web/js/action/reload-cart-action.js +++ /dev/null @@ -1,43 +0,0 @@ -define( - [ - 'checkoutData', - 'Magento_Customer/js/customer-data', - 'Magento_Checkout/js/model/address-converter', - 'Magento_Checkout/js/action/select-billing-address', - 'Magento_Checkout/js/action/select-shipping-address', - 'Magento_Checkout/js/action/select-shipping-method', - 'Magento_Checkout/js/action/get-totals' - ], function ( - checkoutData, - customerData, - addressConverter, - selectBillingAddressAction, - selectShippingAddressAction, - selectShippingMethodAction, - getTotalsAction - ) { - 'use strict'; - - /** - * Update cart and checkout data from backend. - * - * @return {void} - */ - return function () { - customerData.reload(['bold'], false).then((cartData) => { - const billingAddress = addressConverter.formAddressDataToQuoteAddress(cartData.bold.billingAddress); - selectBillingAddressAction(billingAddress); - if (cartData.bold.shippingAddress) { - const shippingAddress = addressConverter.formAddressDataToQuoteAddress(cartData.bold.shippingAddress); - selectShippingAddressAction(shippingAddress); - checkoutData.setSelectedShippingAddress(shippingAddress.getKey()); - } - if (cartData.bold.shippingMethod) { - selectShippingMethodAction(cartData.bold.shippingMethod); - } - getTotalsAction([]); - }).catch((error) => { - console.error('Error reloading customer data', error); - }); - }; - }); diff --git a/view/frontend/web/js/model/fastlane.js b/view/frontend/web/js/model/fastlane.js index 2aca1da..f84d0f0 100644 --- a/view/frontend/web/js/model/fastlane.js +++ b/view/frontend/web/js/model/fastlane.js @@ -1,8 +1,10 @@ define([ 'ko', - 'prototype', + 'Bold_CheckoutPaymentBooster/js/action/general/load-script-action', + 'prototype' ], function ( ko, + loadScriptAction, ) { 'use strict'; @@ -39,7 +41,7 @@ define([ /** * Build Fastlane instance (PPCP / Braintree). * - * @return {Promise<{profile: {showShippingAddressSelector: function}, identity: {lookupCustomerByEmail: function, triggerAuthenticationFlow: function}, FastlanePaymentComponent: function}>} + * @return {Promise} */ getFastlaneInstance: async function (boldPaymentsInstance) { if (!this.isAvailable()) { @@ -99,10 +101,10 @@ define([ * @return {Promise} */ buildBraintreeFastlaneInstance: async function (gatewayData) { - await this.loadScript('bold_braintree_fastlane_hosted_fields', 'hostedFields'); - const client = await this.loadScript('bold_braintree_fastlane_client'); - const dataCollector = await this.loadScript('bold_braintree_fastlane_data_collector'); - const fastlane = await this.loadScript('bold_braintree_fastlane'); + await loadScriptAction('bold_braintree_fastlane_hosted_fields', 'braintree.hostedFields'); + const client = await loadScriptAction('bold_braintree_fastlane_client', 'braintree.client'); + const dataCollector = await loadScriptAction('bold_braintree_fastlane_data_collector'); + const fastlane = await loadScriptAction('bold_braintree_fastlane', 'braintree.fastlane'); const clientInstance = await client.create( { authorization: gatewayData.client_token, @@ -126,24 +128,6 @@ define([ }, ); }, - /** - * Load given script with require js. - * - * @param type - * @param variable - * @return {Promise} - */ - loadScript: async function (type, variable = null) { - return new Promise((resolve, reject) => { - require([type], (src) => { - if (variable) { - window.braintree[variable] = src; - } - resolve(src); - }, reject); - }); - }, - /** * Build PPCP Fastlane instance. * @@ -151,8 +135,8 @@ define([ * @return {Promise} */ buildPPCPFastlaneInstance: async function (gatewayData) { - await this.loadScript('bold_braintree_fastlane_hosted_fields', 'hostedFields'); - await this.loadScript('bold_braintree_fastlane_client', 'client'); + await loadScriptAction('bold_ppcp_fastlane_hosted_fields', 'braintree.hostedFields'); + await loadScriptAction('bold_ppcp_fastlane_client', 'braintree.client'); let debugMode = ''; if (gatewayData.is_test_mode) { debugMode = '&debug=true'; diff --git a/view/frontend/web/js/model/spi.js b/view/frontend/web/js/model/spi.js index f05fd86..7b7d93d 100644 --- a/view/frontend/web/js/model/spi.js +++ b/view/frontend/web/js/model/spi.js @@ -1,37 +1,23 @@ define([ - 'uiRegistry', - 'Bold_CheckoutPaymentBooster/js/action/convert-magento-address', - 'Bold_CheckoutPaymentBooster/js/action/create-wallet-pay-order-action', - 'Bold_CheckoutPaymentBooster/js/action/payment-sca-action', - 'Bold_CheckoutPaymentBooster/js/model/platform-client', - 'checkoutData', - 'Magento_Checkout/js/model/address-converter', - 'Magento_Checkout/js/model/error-processor', 'Magento_Checkout/js/model/quote', - 'Magento_Checkout/js/model/resource-url-manager', - 'Magento_Checkout/js/model/shipping-service', - 'Magento_Checkout/js/model/shipping-save-processor/payload-extender', - 'Magento_Customer/js/customer-data', - 'mage/storage', - 'Bold_CheckoutPaymentBooster/js/model/fastlane', 'Magento_Checkout/js/model/full-screen-loader', + 'Bold_CheckoutPaymentBooster/js/model/fastlane', + 'Bold_CheckoutPaymentBooster/js/action/general/load-script-action', + 'Bold_CheckoutPaymentBooster/js/model/spi/callbacks/on-create-payment-order-callback', + 'Bold_CheckoutPaymentBooster/js/model/spi/callbacks/on-update-payment-order-callback', + 'Bold_CheckoutPaymentBooster/js/model/spi/callbacks/on-require-order-data-callback', + 'Bold_CheckoutPaymentBooster/js/model/spi/callbacks/on-approve-payment-order-callback', + 'Bold_CheckoutPaymentBooster/js/model/spi/callbacks/on-sca-payment-order-callback', ], function ( - registry, - convertMagentoAddress, - createOrderAction, - paymentScaAction, - platformClient, - checkoutData, - addressConverter, - errorProcessor, quote, - resourceUrlManager, - shippingService, - payloadExtender, - customerData, - storage, + fullScreenLoader, fastlane, - fullScreenLoader + loadScriptAction, + onCreatePaymentOrderCallback, + onUpdatePaymentOrderCallback, + onRequireOrderDataCallback, + onApprovePaymentOrderCallback, + onScaPaymentOrderCallback ) { 'use strict'; @@ -41,29 +27,26 @@ define([ * @type {object} */ return { - paymentsInstance: null, - createPaymentsInstanceInProgress: false, - /** - * Load SPI SDK. + * Load SPI SDK and initialize payments client instance. * - * @returns {Promise} + * @returns {Promise<{}>} */ getPaymentsClient: async function () { - if (this.paymentsInstance) { - return this.paymentsInstance; + if (window.boldPaymentsInstance) { + return window.boldPaymentsInstance; } - if (this.createPaymentsInstanceInProgress) { + if (window.createBoldPaymentsInstanceInProgress) { return new Promise((resolve) => { const interval = setInterval(() => { - if (this.paymentsInstance) { + if (window.boldPaymentsInstance) { clearInterval(interval); - resolve(this.paymentsInstance); + resolve(window.boldPaymentsInstance); } }, 100); }); } - this.createPaymentsInstanceInProgress = true; + window.createBoldPaymentsInstanceInProgress = true; require.config({ paths: { bold_payments_sdk: window.checkoutConfig.bold.epsStaticUrl + '/js/payments_sdk', @@ -86,257 +69,97 @@ define([ ], 'callbacks': { 'onCreatePaymentOrder': async (paymentType, paymentPayload) => { - if (paymentType !== 'ppcp') { - return; - } try { - const walletPayResult = await createOrderAction(paymentPayload); - - return { payment_data: { id: walletPayResult[0] }}; + return await onCreatePaymentOrderCallback(paymentType, paymentPayload); } catch (e) { + console.error(e); fullScreenLoader.stopLoader(); - throw 'Unable to create order'; + throw e; } }, 'onUpdatePaymentOrder': async (paymentType, paymentPayload) => { - const paymentData = paymentPayload['payment_data']; - this.updateAddress('shipping', paymentData['shipping_address']); - this.updateShippingMethod(paymentData['shipping_options']); - try { - await this.updateOrder(paymentData['order_id']); + return await onUpdatePaymentOrderCallback(paymentType, paymentPayload); } catch (e) { + console.error(e); fullScreenLoader.stopLoader(); - throw new Error(`Update Payment Order Error ${e.message}`); + throw e; } }, 'onApprovePaymentOrder': async (paymentType, paymentInformation, paymentPayload) => { - const spi = registry.get('index = bold') ?? registry.get('index = bold-express-pay'); - - if (!spi) { - throw new Error('SPI component is not found'); + try { + return await onApprovePaymentOrderCallback(paymentType, paymentInformation, paymentPayload); + } catch (e) { + console.error(e); + fullScreenLoader.stopLoader(); + throw e; } - spi.paymentId(paymentInformation.payment_id); - spi.paymentApprovalData(paymentPayload); - spi.placeOrder({}, jQuery.Event()); }, - 'onScaPaymentOrder': async function (type, payload) { - if (type === 'ppcp') { - const scaResult = await paymentScaAction({ - 'gateway_type': 'ppcp', - 'order_id': payload.order_id, - 'public_order_id': window.checkoutConfig.bold.publicOrderId - }); - return {card: scaResult}; + 'onScaPaymentOrder': async function (paymentType, paymentPayload) { + try { + return await onScaPaymentOrderCallback(paymentType, paymentPayload); + } catch (e) { + console.error(e); + fullScreenLoader.stopLoader(); + throw e; } - fullScreenLoader.stopLoader(); - throw new Error('Unsupported payment type'); - }.bind(this), - 'onRequireOrderData' : async function (requirements) { - const payload = {}; - - for (const requirement of requirements) { - switch (requirement) { - case 'customer': - let billingAddress = quote.billingAddress(); - const email = checkoutData.getValidatedEmailValue() - ? checkoutData.getValidatedEmailValue() - : window.checkoutConfig.customerData.email; - - payload[requirement] = { - first_name: billingAddress.firstname, - last_name: billingAddress.lastname, - email_address: email, - }; - break; - case 'items': - payload[requirement] = quote.getItems().map(item => ({ - amount: parseInt(parseFloat(item.base_price) * 100), - label: item.name - })); - break; - case 'billing_address': - payload[requirement] = convertMagentoAddress(quote.billingAddress()); - break; - case 'shipping_address': - payload[requirement] = convertMagentoAddress(quote.shippingAddress()); - break; - case 'shipping_options': - payload[requirement] = shippingService.getShippingRates().map(option => ({ - label: `${option.carrier_title} - ${option.method_title}`, - amount: option.amount, - id: `${option.carrier_code}_${option.method_code}` - })); - break; - case 'totals': - const totals = quote.getTotals(); - payload[requirement] = { - order_total: totals()['grand_total'], - order_balance: totals()['grand_total'], - shipping_total: totals()['shipping_amount'], - discounts_total: totals()['discount_amount'], - taxes_total: totals()['tax'], - }; - break; - } + }, + 'onRequireOrderData': async function (requirements) { + try { + return onRequireOrderDataCallback(requirements); + } catch (e) { + console.error(e); + fullScreenLoader.stopLoader(); + throw e; } - return payload; }, } }; - - const paymentInstance = new window.bold.Payments(initialData); - this.fastlaneInstance = await fastlane.getFastlaneInstance(paymentInstance); - this.paymentsInstance = paymentInstance; - this.createPaymentsInstanceInProgress = false; - return this.paymentsInstance; - }, - - getFastlaneInstance: async function () { - if (this.fastlaneInstance) { - return this.fastlaneInstance; + const paymentsInstance = new window.bold.Payments(initialData); + window.boldFastlaneInstance = await fastlane.getFastlaneInstance(paymentsInstance); + await paymentsInstance.initialize; + if (paymentsInstance.paymentGateways[0]?.type === 'braintree') { + await this._loadBraintreeScripts(paymentsInstance); //todo: remove as soon as payments.js is adapted to use requirejs } - await this.getPaymentsClient(); - return this.fastlaneInstance; + window.boldPaymentsInstance = paymentsInstance; + window.createBoldPaymentsInstanceInProgress = false; + return window.boldPaymentsInstance; }, - - // TODO: Abstract these functions into action components - - /** - * Update express pay order - * - * @returns {Promise<*>} - */ - updateOrder: async function (orderId) { - let url = 'rest/V1/express_pay/order/update'; - - return new Promise ((resolve, reject) => { - platformClient.post( - url, - { - quoteMaskId: window.checkoutConfig.quoteData.entity_id, - gatewayId: window.checkoutConfig.bold.gatewayId, - paypalOrderId: orderId - } - ).done(() => resolve()).fail(() => reject()); - }); - }, - /** - * Update express pay order + * Make sure Fastlane is initialized before payments instance is created. * - * @param {String} addressType - * @param addressData + * @return {Promise<*>} */ - updateAddress: function(addressType, addressData) { - const directoryData = customerData.get('directory-data'); - let regions; - - try { - regions = directoryData()[addressData['country_code']].regions; - } catch (e) { - regions = null; - } - - let regionId = null; - let regionName = null; - if (regions !== null) { - Object.entries(regions).forEach(([key, value]) => { - if (value.code === addressData['state']) { - regionId = key; - regionName = value.name; - } - }); - } - - let newAddress = addressConverter.formAddressDataToQuoteAddress({ - address_type: addressType, - firstname: addressData['first_name'] ?? null, - lastname: addressData['last_name'] ?? null, - street: [ - addressData['address_line1'] ?? null, - addressData['address_line2'] ?? null, - ], - city: addressData['city'], - region: { - region: regionName, - region_code: addressData['state'], - region_id: regionId - }, - region_id: regionId, - postcode: addressData['postal_code'], - country_id: addressData['country_code'], - email: addressData['email'] ?? null - }); - - if (addressType === 'shipping') { - quote.shippingAddress(newAddress); - } else { - quote.billingAddress(newAddress); + getFastlaneInstance: async function () { + if (window.boldFastlaneInstance) { + return window.boldFastlaneInstance; } + await this.getPaymentsClient(); + return window.boldFastlaneInstance; }, - /** - * Update the quote selected shipping method + * Load Braintree scripts via require js. * - * @param shippingMethod + * @return {Promise} + * @private */ - updateShippingMethod: function (shippingMethod = null) { - let newMethod = null; - - if (shippingMethod !== null) { - let availableMethods = shippingService.getShippingRates().filter((method) => { - let methodId = `${method.carrier_code}_${method.method_code}`; - methodId = methodId.replace(/\s/g, ''); - - return methodId === shippingMethod['id']; - }); - if (availableMethods.length > 0) { - newMethod = availableMethods[0]; - } - } else { - newMethod = shippingService.getShippingRates().first(); + _loadBraintreeScripts: async function (paymentsInstance) { + await loadScriptAction('bold_braintree_client', 'braintree.client'); + await loadScriptAction('bold_braintree_data_collector', 'braintree.dataCollector'); + const gatewayData = paymentsInstance.paymentGateways[0].credentials || null; + if (!gatewayData) { + return; } - - if (newMethod !== null) { - quote.shippingMethod(newMethod); + if (gatewayData.is_paypal_enabled) { + await loadScriptAction('bold_braintree_paypal_checkout', 'braintree.paypalCheckout'); } - - if (quote.guestEmail === null) { - quote.guestEmail = 'test@test.com'; + if (gatewayData.is_google_pay_enabled) { + await loadScriptAction('bold_braintree_google_payment', 'braintree.googlePayment'); + await loadScriptAction('bold_google_pay'); } - - this.saveShippingInformation(); - }, - - /** - * Update backend with new shipping information - * - * @returns {*} - */ - saveShippingInformation: function (saveBillingAddress = false) { - let payload; - - payload = { - addressInformation: { - 'shipping_address': quote.shippingAddress(), - 'shipping_method_code': quote.shippingMethod()['method_code'], - 'shipping_carrier_code': quote.shippingMethod()['carrier_code'] - } - }; - - if (saveBillingAddress) { - payload.addressInformation.billing_address = quote.billingAddress(); + if (gatewayData.is_apple_pay_enabled) { + await loadScriptAction('bold_apple_pay', 'braintree.applePay'); } - - payloadExtender(payload); - - return storage.post( - resourceUrlManager.getUrlForSetShippingInformation(quote), - JSON.stringify(payload) - ).fail((response) => { - errorProcessor.process(response); - }); - } + }, }; }); diff --git a/view/frontend/web/js/model/spi/callbacks/on-approve-payment-order-callback.js b/view/frontend/web/js/model/spi/callbacks/on-approve-payment-order-callback.js new file mode 100644 index 0000000..b578b92 --- /dev/null +++ b/view/frontend/web/js/model/spi/callbacks/on-approve-payment-order-callback.js @@ -0,0 +1,63 @@ +define( + [ + 'uiRegistry', + 'jquery', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/action/place-order', + 'Magento_Checkout/js/action/redirect-on-success', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/update-quote-ppcp-action', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/update-quote-braintree-action', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/save-shipping-information-action', + ], + function ( + registry, + $, + quote, + placeOrderAction, + redirectOnSuccessAction, + updateQuotePPCPAction, + updateQuoteBraintreeAction, + saveShippingInformationAction + ) { + 'use strict'; + + /** + * Place express-order action. + * + * @param {string} paymentType + * @param {{}} paymentInformation + * @param {{}} paymentApprovalData + * @return {Promise} + */ + return async function (paymentType, paymentInformation, paymentApprovalData) { + if (paymentApprovalData === null) { + console.error('Express Pay payment data is not set.'); + return; + } + const paymentMethodData = { + method: 'bold', + }; + if (paymentType === 'ppcp') { + paymentMethodData['additional_data'] = { + order_id: paymentApprovalData?.payment_data.order_id + }; + await updateQuotePPCPAction(paymentApprovalData); + } else { + await updateQuoteBraintreeAction(paymentInformation, paymentApprovalData); + } + try { + await saveShippingInformationAction(true); + } catch (error) { + console.error('Could not save shipping information for Express Pay order.', error); + return; + } + const messageContainer = registry.get('checkout.errors').messageContainer; + $.when(placeOrderAction(paymentMethodData, messageContainer)) + .done( + function () { + redirectOnSuccessAction.execute(); + } + ); + }; + } +); diff --git a/view/frontend/web/js/model/spi/callbacks/on-create-payment-order-callback.js b/view/frontend/web/js/model/spi/callbacks/on-create-payment-order-callback.js new file mode 100644 index 0000000..161ecf2 --- /dev/null +++ b/view/frontend/web/js/model/spi/callbacks/on-create-payment-order-callback.js @@ -0,0 +1,28 @@ +define( + [ + 'Bold_CheckoutPaymentBooster/js/action/express-pay/create-wallet-pay-order-action' + ], + function ( + createWalletPayOrderAction + ) { + 'use strict'; + + /** + * Callback function for creating wallet pay order. + * + * @param {String} paymentType + * @param {Object} paymentOrder + */ + return async function (paymentType, paymentPayload) { + if (paymentType !== 'ppcp') { + return; + } + const walletPayResult = await createWalletPayOrderAction(paymentPayload); + return { + payment_data: { + id: walletPayResult[0] + } + }; + }; + } +); diff --git a/view/frontend/web/js/model/spi/callbacks/on-require-order-data-callback.js b/view/frontend/web/js/model/spi/callbacks/on-require-order-data-callback.js new file mode 100644 index 0000000..f149e7e --- /dev/null +++ b/view/frontend/web/js/model/spi/callbacks/on-require-order-data-callback.js @@ -0,0 +1,20 @@ +define( + [ + 'Bold_CheckoutPaymentBooster/js/action/express-pay/get-required-order-data-action' + ], + function ( + getRequiredOrderDataAction + ) { + 'use strict'; + + /** + * Callback function for creating wallet pay order. + * + * @param {String} paymentType + * @param {Object} paymentOrder + */ + return function (requirements) { + return getRequiredOrderDataAction(requirements); + }; + } +); diff --git a/view/frontend/web/js/model/spi/callbacks/on-sca-payment-order-callback.js b/view/frontend/web/js/model/spi/callbacks/on-sca-payment-order-callback.js new file mode 100644 index 0000000..9eea05a --- /dev/null +++ b/view/frontend/web/js/model/spi/callbacks/on-sca-payment-order-callback.js @@ -0,0 +1,26 @@ +define( + [ + 'Bold_CheckoutPaymentBooster/js/action/express-pay/payment-sca-action' + ], + function ( + paymentScaAction + ) { + 'use strict'; + + /** + * Callback function for approving payment order. + * + */ + return async function (paymentType, paymentPayload) { + if (paymentType === 'ppcp') { + const scaResult = await paymentScaAction({ + 'gateway_type': 'ppcp', + 'order_id': paymentPayload.order_id, + 'public_order_id': window.checkoutConfig.bold.publicOrderId + }); + return {card: scaResult}; + } + throw new Error('Unsupported payment type'); + }; + } +); diff --git a/view/frontend/web/js/model/spi/callbacks/on-update-payment-order-callback.js b/view/frontend/web/js/model/spi/callbacks/on-update-payment-order-callback.js new file mode 100644 index 0000000..5474ac0 --- /dev/null +++ b/view/frontend/web/js/model/spi/callbacks/on-update-payment-order-callback.js @@ -0,0 +1,36 @@ +define( + [ + 'Bold_CheckoutPaymentBooster/js/action/express-pay/update-quote-address-action', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/update-quote-shipping-method-action', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/update-wallet-pay-order-action', + 'Bold_CheckoutPaymentBooster/js/action/express-pay/get-required-order-data-action', + ], + function ( + updateQuoteAddressAction, + updateQuoteShippingMethodAction, + updateWalletPayOrderAction, + getRequiredOrderDataAction + ) { + 'use strict'; + + /** + * Callback function for updating payment order. + * + * @param {String} paymentType + * @param {Object} paymentOrder + */ + return async function (paymentType, paymentPayload) { + const paymentData = paymentPayload['payment_data']; + if (paymentData['shipping_address']) { + updateQuoteAddressAction('shipping', paymentData['shipping_address']); + } + updateQuoteShippingMethodAction(paymentData['shipping_options']); + if (paymentType === 'ppcp') { + await updateWalletPayOrderAction(paymentData['order_id']); + } + return getRequiredOrderDataAction( + paymentPayload['require_order_data'] || [] + ); + }; + } +); diff --git a/view/frontend/web/js/model/step-navigator-mixin.js b/view/frontend/web/js/model/step-navigator-mixin.js index ab4e2ff..995e6ed 100644 --- a/view/frontend/web/js/model/step-navigator-mixin.js +++ b/view/frontend/web/js/model/step-navigator-mixin.js @@ -6,10 +6,10 @@ define([ let mixin = { handleHash: function (originalFn) { - var hashString = window.location.hash.replace('#', ''); - if (hashString.indexOf('place_order') > -1) { + const hashString = window.location.hash.replace('#', ''); + if (hashString.indexOf('place_order') > -1) { window.checkoutConfig.bold.scaRedirect = true; - window.location.hash = '#payment'; + window.location.hash = '#payment'; } return originalFn(); } @@ -18,4 +18,4 @@ define([ return function (target) { return wrapper.extend(target, mixin); }; -}); \ No newline at end of file +}); diff --git a/view/frontend/web/js/view/bold-express-pay.js b/view/frontend/web/js/view/bold-express-pay.js index 065e804..9f8d423 100644 --- a/view/frontend/web/js/view/bold-express-pay.js +++ b/view/frontend/web/js/view/bold-express-pay.js @@ -2,24 +2,14 @@ define([ 'uiComponent', 'ko', 'jquery', + 'underscore', 'Bold_CheckoutPaymentBooster/js/model/spi', - 'Magento_Checkout/js/model/quote', - 'checkoutData', - 'uiRegistry', - 'Bold_CheckoutPaymentBooster/js/action/get-express-pay-order-action', - 'Magento_Checkout/js/action/place-order', - 'Magento_Checkout/js/action/redirect-on-success' ], function ( Component, ko, $, + _, spi, - quote, - checkoutData, - registry, - getExpressPayOrderAction, - placeOrderAction, - redirectOnSuccessAction ) { 'use strict'; @@ -61,7 +51,7 @@ define([ } }, - _renderExpressPayments: function() { + _renderExpressPayments: function () { const containerId = 'express-pay-buttons'; const observer = new MutationObserver(async () => { let boldPaymentsInstance; @@ -77,7 +67,7 @@ define([ return; } - const allowedCountries = window.checkoutConfig.bold?.countries ?? []; + const allowedCountries = this._getAllowedCountryCodes(); const walletOptions = { shopName: window.checkoutConfig.bold?.shopName ?? '', isPhoneRequired: window.checkoutConfig.bold?.isPhoneRequired ?? true, @@ -93,73 +83,12 @@ define([ subtree: true }); }, - - placeOrder: async function () { - const paymentApprovalData = this.paymentApprovalData(); - const paymentMethodData = { - method: 'bold', - additional_data: { - order_id: paymentApprovalData?.payment_data.order_id - } - }; - const messageContainer = registry.get('checkout.errors').messageContainer; - let order; - - if (paymentApprovalData === null) { - console.error('Express Pay payment data is not set.'); - - return; - } - - try { - order = await getExpressPayOrderAction( - paymentApprovalData.gateway_id, - paymentApprovalData.payment_data.order_id - ); - } catch (error) { - console.error('Could not retrieve Express Pay order.', error); - - return; - } - - quote.guestEmail = order.email; - - spi.updateAddress('shipping', this._convertAddress(order.shipping_address, order)); - spi.updateAddress('billing', this._convertAddress(order.billing_address, order)); - - try { - await spi.saveShippingInformation(true); - } catch (error) { - console.error('Could not save shipping information for Express Pay order.', error); - - return; - } - - $.when(placeOrderAction(paymentMethodData, messageContainer)) - .done( - function () { - redirectOnSuccessAction.execute(); - } - ); - }, - - /** - * @param {Object} order - * @param {Object} address - * @returns {Object} - * @private - */ - _convertAddress: function (address, order) { - address.first_name = order.first_name; - address.last_name = order.last_name; - address.state = address.province; - address.country_code = address.country; - address.email = order.email; - - delete address.province; - delete address.country; - - return address; + _getAllowedCountryCodes: function () { + const countryCodes = []; + _.each(window.checkoutConfig.bold?.countries, function (countryData) { + countryCodes.push(countryData.value); + }); + return countryCodes; }, }); }); diff --git a/view/frontend/web/js/view/form/element/email/fastlane-mixin.js b/view/frontend/web/js/view/form/element/email/fastlane-mixin.js index 477fa25..303852f 100644 --- a/view/frontend/web/js/view/form/element/email/fastlane-mixin.js +++ b/view/frontend/web/js/view/form/element/email/fastlane-mixin.js @@ -9,8 +9,8 @@ define( 'uiRegistry', 'Magento_Checkout/js/model/full-screen-loader', 'checkoutData', - 'Bold_CheckoutPaymentBooster/js/action/set-quote-shipping-address', - 'Bold_CheckoutPaymentBooster/js/action/reset-shipping-address', + 'Bold_CheckoutPaymentBooster/js/action/fastlane/set-quote-shipping-address-action', + 'Bold_CheckoutPaymentBooster/js/action/fastlane/reset-shipping-address-action', 'Magento_Checkout/js/model/quote' ], function ( spi, diff --git a/view/frontend/web/js/view/payment/method-renderer/bold-fastlane.js b/view/frontend/web/js/view/payment/method-renderer/bold-fastlane.js index 80c819c..5f8745f 100644 --- a/view/frontend/web/js/view/payment/method-renderer/bold-fastlane.js +++ b/view/frontend/web/js/view/payment/method-renderer/bold-fastlane.js @@ -7,7 +7,7 @@ define( 'Bold_CheckoutPaymentBooster/js/model/bold-frontend-client', 'Bold_CheckoutPaymentBooster/js/model/spi', 'Bold_CheckoutPaymentBooster/js/model/fastlane', - 'Bold_CheckoutPaymentBooster/js/action/convert-fastlane-address', + 'Bold_CheckoutPaymentBooster/js/action/fastlane/convert-fastlane-address-action', 'Magento_Checkout/js/model/quote', 'checkoutData', 'Magento_Checkout/js/model/full-screen-loader', @@ -15,7 +15,7 @@ define( 'underscore', 'ko', 'mage/translate', - 'Bold_CheckoutPaymentBooster/js/action/eps-tokenize-action', + 'Bold_CheckoutPaymentBooster/js/action/fastlane/eps-tokenize-action', ], function ( MagentoPayment, errorProcessor, diff --git a/view/frontend/web/js/view/payment/method-renderer/bold-spi.js b/view/frontend/web/js/view/payment/method-renderer/bold-spi.js index 187ca7f..f932b68 100644 --- a/view/frontend/web/js/view/payment/method-renderer/bold-spi.js +++ b/view/frontend/web/js/view/payment/method-renderer/bold-spi.js @@ -12,7 +12,7 @@ define([ 'Bold_CheckoutPaymentBooster/js/model/spi', 'Bold_CheckoutPaymentBooster/js/model/platform-client', 'Bold_CheckoutPaymentBooster/js/model/fastlane', - 'Bold_CheckoutPaymentBooster/js/action/hydrate-order-action', + 'Bold_CheckoutPaymentBooster/js/action/general/hydrate-order-action', ], function ( DefaultPaymentComponent, quote, @@ -120,18 +120,12 @@ define([ /** @inheritdoc */ placeOrder: function (data, event) { fullscreenLoader.startLoader(); - const callback = this._super.bind(this); + const placeMagentoOrder = this._super.bind(this); if (this.paymentId()) { - callback(data, event); - return; + return placeMagentoOrder(data, event); } - - this.tokenize() - this.paymentId.subscribe((id) => { - if (id != null) { - callback(data, event); - } - }); + this.tokenize(); + return false; }, /** @@ -208,8 +202,13 @@ define([ this.isSpiLoading(false); break; case 'EVENT_SPI_TOKENIZED': - this.paymentId(data.payload?.payload?.data?.payment_id); - this.placeOrder(); + const paymentId = data.payload?.payload?.data?.payment_id; + if (!paymentId) { + fullscreenLoader.stopLoader(); + return; + } + this.paymentId(paymentId); + this.placeOrder({}, jQuery.Event()); break; case 'EVENT_SPI_TOKENIZE_FAILED': this.paymentId(null); diff --git a/view/frontend/web/js/view/shipping-address/address-renderer/default.js b/view/frontend/web/js/view/shipping-address/address-renderer/default.js index b8a09d0..84c99de 100644 --- a/view/frontend/web/js/view/shipping-address/address-renderer/default.js +++ b/view/frontend/web/js/view/shipping-address/address-renderer/default.js @@ -1,6 +1,6 @@ define([ 'Magento_Checkout/js/view/shipping-address/address-renderer/default', - 'Bold_CheckoutPaymentBooster/js/action/show-fastlane-shipping-address-form' + 'Bold_CheckoutPaymentBooster/js/action/fastlane/show-fastlane-shipping-address-form-action' ], function ( MagentoAddressRenderer, showFastlaneAddressFormAction diff --git a/view/frontend/web/js/view/shipping-address/list.js b/view/frontend/web/js/view/shipping-address/list.js index 6164e7c..9639b19 100644 --- a/view/frontend/web/js/view/shipping-address/list.js +++ b/view/frontend/web/js/view/shipping-address/list.js @@ -3,7 +3,7 @@ define( 'ko', 'Magento_Checkout/js/view/shipping-address/list', 'Magento_Customer/js/model/address-list', - 'Bold_CheckoutPaymentBooster/js/action/show-shipping-address-form', + 'Bold_CheckoutPaymentBooster/js/action/fastlane/show-shipping-address-form-action', 'Bold_CheckoutPaymentBooster/js/model/spi', 'Bold_CheckoutPaymentBooster/js/model/fastlane', 'Magento_Checkout/js/model/quote'