diff --git a/.gitignore b/.gitignore index ecacae7..5f8c1cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.vscode node_modules cartridges/int_afterpay_sfra/cartridge/static/default/css cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpay.js diff --git a/cartridges/int_afterpay_core/cartridge/scripts/brandMapping.json b/cartridges/int_afterpay_core/cartridge/scripts/brandMapping.json index 8f2e979..aa1f9f7 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/brandMapping.json +++ b/cartridges/int_afterpay_core/cartridge/scripts/brandMapping.json @@ -6,5 +6,9 @@ "clearpay": { "paymentMethod": "CLEARPAY", "paymentProcessor": "*/cartridge/scripts/payment/processor/CLEARPAY" + }, + "cashapp": { + "paymentMethod": "CASHAPPPAY", + "paymentProcessor": "*/cartridge/scripts/payment/processor/CASHAPPPAY" } -} \ No newline at end of file +} diff --git a/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayGetToken.js b/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayGetToken.js index 193909d..6df1677 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayGetToken.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayGetToken.js @@ -9,10 +9,11 @@ var Logger = LogUtils.getLogger('afterpayGetToken'); * @param {Object} basket - basket * @returns {Object} - Token */ -function getToken(basket) { +function getToken(basket,isCashAppPay) { var AfterpayToken; + var isCashAppPay = isCashAppPay || false; try { - orderCreateService.generateRequest(basket); + orderCreateService.generateRequest(basket,isCashAppPay); var response = orderCreateService.getResponse(); var res = new TokenModel(); diff --git a/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayHandlePaymentOrder.js b/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayHandlePaymentOrder.js index 6769266..56b6e39 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayHandlePaymentOrder.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayHandlePaymentOrder.js @@ -20,16 +20,17 @@ var parsePaymentStatus = function (paymentStatus) { * @param {number} paymentStatus - payment status * @returns {number} - payment status */ -function getPaymentStatus(order, paymentStatus, expressCheckoutModel) { +function getPaymentStatus(order, paymentStatus, expressCheckoutModel, isCashAppPay) { var parsedPaymentStatus = parsePaymentStatus(paymentStatus); + var isCashAppPay = isCashAppPay || false; Logger.debug('parsed payment status : ' + parsedPaymentStatus); var paymentResult; try { - paymentResult = baseUpdateOrderService.handleOrder(order, parsedPaymentStatus, expressCheckoutModel); + paymentResult = baseUpdateOrderService.handleOrder(order, parsedPaymentStatus, expressCheckoutModel, isCashAppPay); if (paymentResult && paymentResult.status === 'DECLINED') { parsedPaymentStatus = paymentResult.status; } - afterpayUpdateOrder.handleUpdateOrder(order, paymentResult, sitePreferencesUtilities.getPaymentMode().value); + afterpayUpdateOrder.handleUpdateOrder(order, paymentResult, sitePreferencesUtilities.getPaymentMode().value,isCashAppPay); Logger.debug('UpdatedOrder service status : ' + parsedPaymentStatus); } catch (exception) { Logger.error('Exception occured while updating order status ' + exception); diff --git a/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayUpdateOrder.js b/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayUpdateOrder.js index ea98249..aab9cb7 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayUpdateOrder.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayUpdateOrder.js @@ -2,7 +2,6 @@ var afterpayConstants = require('*/cartridge/scripts/util/afterpayConstants'); var apUtilities = require('*/cartridge/scripts/util/afterpayUtilities'); var apCheckoutUtilities = apUtilities.checkoutUtilities; var Transaction = require('dw/system/Transaction'); -var Logger = require('dw/system/Logger'); var afterpayUpdateOrder = { /** @@ -11,14 +10,14 @@ var afterpayUpdateOrder = { * @param {Object} paymentResult - payment result * @param {'DIRECT_CAPTURE'|'AUTHORISE'} paymentMode - payment mode */ - handleUpdateOrder: function (order, paymentResult, paymentMode) { + handleUpdateOrder: function (order, paymentResult, paymentMode, isCashAppPay) { var paymentTransaction; try { - paymentTransaction = this.getPaymentTransaction(order); + paymentTransaction = this.getPaymentTransaction(order,isCashAppPay); if (paymentResult.status !== afterpayConstants.PAYMENT_STATUS.DECLINED) { - this.savePaymentTransaction(paymentTransaction, paymentResult, paymentMode); - this.saveOrder(order, paymentResult); + this.savePaymentTransaction(paymentTransaction, paymentResult, paymentMode, isCashAppPay); + this.saveOrder(order, paymentResult, isCashAppPay); } else { this.savePaymentTransactionDeclined(paymentTransaction, paymentMode); } @@ -36,7 +35,7 @@ var afterpayUpdateOrder = { * @returns {dw.order.PaymentTransaction} - transaction */ // eslint-disable-next-line no-unused-vars - savePaymentTransaction: function (paymentTransaction, paymentResult, paymentMode) { + savePaymentTransaction: function (paymentTransaction, paymentResult, paymentMode, isCashAppPay) { var Money = require('dw/value/Money'); var BrandUtilities = apUtilities.brandUtilities; var payTrans = paymentTransaction; @@ -44,7 +43,7 @@ var afterpayUpdateOrder = { Transaction.wrap(function () { payTrans.setTransactionID(paymentResult.id || null); - payTrans.setPaymentProcessor(afterpayUpdateOrder.getPaymentProcessor()); + payTrans.setPaymentProcessor(afterpayUpdateOrder.getPaymentProcessor(isCashAppPay)); payTrans.custom.apPaymentID = paymentResult.id || null; payTrans.custom.apPaymentMode = paymentMode; payTrans.custom.apCountryCode = BrandUtilities.getCountryCode(); @@ -67,9 +66,9 @@ var afterpayUpdateOrder = { * @param {dw.order.Order} order - order * @returns {dw.order.PaymentTransaction} - payment transaction */ - getPaymentTransaction: function (order) { + getPaymentTransaction: function (order,isCashAppPay) { var paymentTransaction; - var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); + var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(isCashAppPay); if (!paymentMethodName) { return null; @@ -88,9 +87,9 @@ var afterpayUpdateOrder = { * retrieves payment processor * @returns {dw.order.PaymentProcessor} - processor */ - getPaymentProcessor: function () { + getPaymentProcessor: function (isCashAppPay) { var PaymentMgr = require('dw/order/PaymentMgr'); - var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); + var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(isCashAppPay); if (!paymentMethodName) { return null; @@ -105,11 +104,16 @@ var afterpayUpdateOrder = { * @param {Object} paymentResult - result * @returns {dw.order.Order} - order */ - saveOrder: function (order, paymentResult) { + saveOrder: function (order, paymentResult, isCashAppPay) { var Order = require('dw/order/Order'); var outOrder = order; Transaction.begin(); - outOrder.custom.apIsAfterpayOrder = true; + if(!isCashAppPay){ + outOrder.custom.apIsAfterpayOrder = true; + } else { + outOrder.custom.isCashAppPayOrder = true; + } + if (paymentResult.status === afterpayConstants.PAYMENT_STATUS.APPROVED) { outOrder.setPaymentStatus(Order.PAYMENT_STATUS_PAID); } else { @@ -125,10 +129,10 @@ var afterpayUpdateOrder = { * @param {'DIRECT_CAPTURE'|'AUTHORISE'} paymentMode - payment mode * @returns {dw.order.PaymentTransaction} - transaction */ - savePaymentTransactionDeclined: function (paymentTransaction, paymentMode) { + savePaymentTransactionDeclined: function (paymentTransaction, paymentMode,isCashAppPay) { var payTrans = paymentTransaction; Transaction.begin(); - payTrans.setPaymentProcessor(this.getPaymentProcessor()); + payTrans.setPaymentProcessor(this.getPaymentProcessor(isCashAppPay)); payTrans.custom.apPaymentMode = paymentMode; payTrans.custom.apInitialStatus = afterpayConstants.PAYMENT_STATUS.DECLINED; payTrans.custom.apToken = null; diff --git a/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus.js b/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus.js index d6b6ce1..57df61a 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus.js @@ -23,9 +23,12 @@ function parsePreapprovalResult(parameter) { * @param {Object} preapprovalModel - preApproval Model * @param {Object} lineItemCtnr - line Item Container */ -function updatePreapprovalStatus(preapprovalModel, lineItemCtnr) { +function updatePreapprovalStatus(preapprovalModel, lineItemCtnr, parameterMap) { const { checkoutUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); - var paymentTransaction = checkoutUtilities.getPaymentTransaction(lineItemCtnr); + var isCashAppPay = parameterMap.isCashAppPay || false; + var paymentMethodName = checkoutUtilities.getPaymentMethodName(isCashAppPay); + var paymentInstrument = lineItemCtnr.getPaymentInstruments(paymentMethodName)[0]; + var paymentTransaction = paymentInstrument ? paymentInstrument.getPaymentTransaction() : null; if (paymentTransaction) { Logger.debug('Payment status after token generation : ' + preapprovalModel.status); Transaction.begin(); @@ -52,7 +55,7 @@ function getPreApprovalResult(lineItemCtnr, parameterMap) { return { error: true }; } try { - updatePreapprovalStatus(preapprovalModel, lineItemCtnr); + updatePreapprovalStatus(preapprovalModel, lineItemCtnr, parameterMap); } catch (exception) { var e = exception; Logger.error('Update payment transaction: ' + e); diff --git a/cartridges/int_afterpay_core/cartridge/scripts/hooks.json b/cartridges/int_afterpay_core/cartridge/scripts/hooks.json new file mode 100644 index 0000000..79adeb3 --- /dev/null +++ b/cartridges/int_afterpay_core/cartridge/scripts/hooks.json @@ -0,0 +1,3 @@ +{ + "hooks": [] +} diff --git a/cartridges/int_afterpay_core/cartridge/scripts/logic/services/afterpayHttpService.js b/cartridges/int_afterpay_core/cartridge/scripts/logic/services/afterpayHttpService.js index 53dbc26..3dfa314 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/logic/services/afterpayHttpService.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/logic/services/afterpayHttpService.js @@ -42,12 +42,13 @@ function getAfterpayHttpService() { service.setRequestMethod(requestBody.requestMethod); service.addHeader('Content-Type', 'application/json'); - const afterpayCartridge = 'AfterpayCartridge/23.1.0'; - const merchantID = 'Merchant/' + service.configuration.credential.user; + const afterpayCartridge = 'AfterpayCartridge/23.2.0-beta.1'; + const merchantID = service.configuration.credential.user; const siteURL = URLUtils.httpsHome().toString(); const storeFront = Site.getCurrent().getID(); const hostURL = siteURL.substring(0, siteURL.indexOf('/', 14)); const compatibilityMode = dw.system.System.getCompatibilityMode(); + const cashAppEnabled = apSitePreferencesUtilities.isCashAppEnabled() ? '1' : '0'; var storefrontVersion = ''; if (storeFront.includes('SiteGenesis')) { storefrontVersion = Resource.msg('revisioninfo.revisionnumber', 'revisioninfo', null); @@ -55,7 +56,7 @@ function getAfterpayHttpService() { storefrontVersion = Resource.msg('global.version.number', 'version', null); } - var userAgent = afterpayCartridge + ' (SalesforceCommmerceCloud; ' + storeFront + '/' + storefrontVersion + '; CompatibilityMode/' + compatibilityMode + '; Merchant/' + merchantID + ') ' + hostURL; + var userAgent = afterpayCartridge + ' (SalesforceCommmerceCloud; ' + storeFront + '/' + storefrontVersion + '; CompatibilityMode/' + compatibilityMode + '; Merchant/' + merchantID + '; CashAppEnabled/' + cashAppEnabled + ') ' + hostURL; service.addHeader('User-Agent', userAgent); diff --git a/cartridges/int_afterpay_core/cartridge/scripts/logic/services/afterpayUpdateOrderService.js b/cartridges/int_afterpay_core/cartridge/scripts/logic/services/afterpayUpdateOrderService.js index a335f5e..8d891be 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/logic/services/afterpayUpdateOrderService.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/logic/services/afterpayUpdateOrderService.js @@ -4,7 +4,7 @@ var afterpayDirectCaptureService = require('*/cartridge/scripts/logic/services/a var afterpayAuthoriseService = require('*/cartridge/scripts/logic/services/afterpayAuthorisePaymentService'); var PAYMENT_MODE = require('*/cartridge/scripts/util/afterpayConstants').PAYMENT_MODE; var PAYMENT_STATUS = require('*/cartridge/scripts/util/afterpayConstants').PAYMENT_STATUS; -var { checkoutUtilities: apCheckoutUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); +var { checkoutUtilities: apCheckoutUtilities, sitePreferencesUtilities : apSitePreferencesUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); var Site = require('dw/system/Site'); var Resource = require('dw/web/Resource'); @@ -16,29 +16,29 @@ var OrderMgr = require('dw/order/OrderMgr'); * processes all the transaction details related to the payment and order */ var UpdateOrderService = { - handleOrder: function (order, paymentStatus, expressCheckoutModel) { + handleOrder: function (order, paymentStatus, expressCheckoutModel,isCashAppPay) { + var isCashAppPay = isCashAppPay || false var authoriseDirectCaptureResult = null; if (paymentStatus === PAYMENT_STATUS.DECLINED) { authoriseDirectCaptureResult = this.updateDeclinedOrder(order); } else if (paymentStatus === PAYMENT_STATUS.FAILED) { authoriseDirectCaptureResult = this.updateFailedOrder(order); } else if (paymentStatus === PAYMENT_STATUS.APPROVED) { - authoriseDirectCaptureResult = this.handleApprovalOrder(order, expressCheckoutModel); + authoriseDirectCaptureResult = this.handleApprovalOrder(order, expressCheckoutModel, isCashAppPay); } else if (paymentStatus === PAYMENT_STATUS.PENDING) { authoriseDirectCaptureResult = this.handlePendingOrder(order); } return authoriseDirectCaptureResult; }, - handleApprovalOrder: function (order, expressCheckoutModel) { - var paymentAmount = this.getPaymentAmount(order); + handleApprovalOrder: function (order, expressCheckoutModel,isCashAppPay) { + var paymentAmount = this.getPaymentAmount(order,isCashAppPay); // express checkout needs payment amount, even for direct capture. // express checkout with deferred flows needs checksum and amount // these are all in expressCheckoutModel var authoriseDirectCaptureResult = null; var authoriseDirectCaptureService = this.getAuthoriseDirectCaptureService(order); - var requestValues = authoriseDirectCaptureService.generateRequest(order, this.getToken(order), order.orderNo, paymentAmount, expressCheckoutModel); - + var requestValues = authoriseDirectCaptureService.generateRequest(order, this.getToken(order,isCashAppPay), order.orderNo, paymentAmount, expressCheckoutModel); try { authoriseDirectCaptureResult = authoriseDirectCaptureService.getResponse(requestValues.requestUrl, requestValues.requestBody); } catch (e) { @@ -53,7 +53,7 @@ var UpdateOrderService = { }, getAuthoriseDirectCaptureService: function (order) { - var paymentMode = apCheckoutUtilities.getPaymentMode(order); + var paymentMode = apSitePreferencesUtilities.getPaymentMode(); if (paymentMode === PAYMENT_MODE.AUTHORISE) { return afterpayAuthoriseService; } @@ -90,9 +90,9 @@ var UpdateOrderService = { return apPaymentID; }, - getToken: function (order) { + getToken: function (order,isCashAppPay) { var apToken; - var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); + var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(isCashAppPay); if (!paymentMethodName) { return null; @@ -110,8 +110,8 @@ var UpdateOrderService = { return apToken; }, // Need amount for express checkouts - getPaymentAmount: function (order) { - var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); + getPaymentAmount: function (order,isCashAppPay) { + var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(isCashAppPay); return order.getPaymentInstruments(paymentMethodName)[0].getPaymentTransaction().amount; }, updateOrder: function (order, status) { @@ -135,6 +135,7 @@ var UpdateOrderService = { }, updateApprovedOrder: function (order, containerView) { + var containerView = containerView || 'basket' Transaction.begin(); order.setPaymentStatus(Order.PAYMENT_STATUS_PAID); Transaction.commit(); @@ -161,7 +162,7 @@ var UpdateOrderService = { var orderModel = new OrderModel(order, { containerView: containerView || 'basket', - countryCode: order.getBillingAddress().getCountryCode().value + countryCode: brandUtilities.getCountryCode() }); var orderObject = { order: orderModel }; diff --git a/cartridges/int_afterpay_core/cartridge/scripts/order/expressOrderRequestBuilder.js b/cartridges/int_afterpay_core/cartridge/scripts/order/expressOrderRequestBuilder.js index b4c2ba6..6740302 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/order/expressOrderRequestBuilder.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/order/expressOrderRequestBuilder.js @@ -132,20 +132,19 @@ OrderRequestBuilder.prototype.buildItems = function (basket) { var item = new LineItem(); var product = li.product; - // Some lineitems may not be products - // e.g. extended warranties + // Some lineitems may not be products + // e.g. extended warranties if (!product) { item.name = li.getLineItemText(); - item.quantity = li.getQuantity().value; - item.price.amount = li.adjustedNetPrice.value; + item.sku = li.productID; item.price.currency = li.adjustedNetPrice.currencyCode; } else { - item.name = product.name; - item.sku = product.ID; - item.quantity = li.getQuantity().value; - item.price.amount = product.getPriceModel().getPrice().value; - item.price.currency = product.getPriceModel().getPrice().currencyCode; + item.name = product.name; + item.sku = product.ID; + item.price.currency = product.getPriceModel().getPrice().currencyCode; } + item.quantity = li.getQuantity().value; + item.price.amount = (li.adjustedPrice.value/item.quantity).toString(); return item; }); diff --git a/cartridges/int_afterpay_core/cartridge/scripts/order/orderRequestBuilder.js b/cartridges/int_afterpay_core/cartridge/scripts/order/orderRequestBuilder.js index a73b672..4ce504f 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/order/orderRequestBuilder.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/order/orderRequestBuilder.js @@ -67,8 +67,8 @@ OrderRequestBuilder.prototype._buildAddress = function (type, address) { * @param {dw.order.Basket} basket - source cart * @returns {dw.order.PaymentTransaction} - payment transaction associated with provided basket */ -OrderRequestBuilder.prototype._getPaymentTransaction = function (basket) { - var paymentMethod = checkoutUtilities.getPaymentMethodName(); +OrderRequestBuilder.prototype._getPaymentTransaction = function (basket, isCashAppPay) { + var paymentMethod = checkoutUtilities.getPaymentMethodName(isCashAppPay); if (!paymentMethod) { return null; @@ -94,22 +94,20 @@ OrderRequestBuilder.prototype.buildRequest = function (params) { throw new Error(this._log(e)); } - var basket = params.basket; - var url = params.url; - var requestMethod = params.requestMethod; - + var { basket, isCashAppPay, requestMethod } = params; return this.init() .buildConsumer(basket) .buildBilling(basket) .buildShipping(basket) .buildItems(basket) .applyDiscounts(basket) - .buildTotalAmount(basket) + .buildTotalAmount(basket,isCashAppPay) .buildShippingAmount(basket) .buildTotalTax(basket) - .buildMerchantInformation(url) + .buildMerchantInformation(isCashAppPay) .buildPurchaseCountry() - .buildRequestMethod(requestMethod); + .buildRequestMethod(requestMethod) + .buildCashAppPay(isCashAppPay); }; /** @@ -242,16 +240,14 @@ OrderRequestBuilder.prototype.buildItems = function (basket) { if (!product) { item.name = li.getLineItemText(); item.sku = li.productID; - item.quantity = li.getQuantity().value; - item.price.amount = li.adjustedNetPrice.value; item.price.currency = li.adjustedNetPrice.currencyCode; } else { item.name = product.name; item.sku = product.ID; - item.quantity = li.getQuantity().value; - item.price.amount = product.getPriceModel().getPrice().value; item.price.currency = product.getPriceModel().getPrice().currencyCode; - } + } + item.quantity = li.getQuantity().value; + item.price.amount = (li.adjustedPrice.value/item.quantity).toString(); return item; }); return this; @@ -262,13 +258,25 @@ OrderRequestBuilder.prototype.buildItems = function (basket) { * @param {string} url - url * @returns {Object} - this object */ -OrderRequestBuilder.prototype.buildMerchantInformation = function (url) { - this.context.merchant.redirectConfirmUrl = !empty(url) ? url : sitePreferencesUtilities.getRedirectConfirmUrl(); - this.context.merchant.redirectCancelUrl = !empty(url) ? url : sitePreferencesUtilities.getRedirectCancelUrl(); +OrderRequestBuilder.prototype.buildMerchantInformation = function (isCashAppPay) { + var merchantURL = sitePreferencesUtilities.getRedirectConfirmUrl(isCashAppPay); + this.context.merchant.redirectConfirmUrl = merchantURL; + this.context.merchant.redirectCancelUrl = merchantURL; return this; }; +/** + * builds CashAppPay + * @returns {Object} - this object + */ + OrderRequestBuilder.prototype.buildCashAppPay = function (isCashAppPay) { + if(isCashAppPay){ + this.context.isCashAppPay = 'true'; + } + return this; +}; + /** * builds discounts details * @param {Object} basket - basket @@ -307,9 +315,8 @@ OrderRequestBuilder.prototype.applyDiscounts = function (basket) { * @returns {Object} - this object */ // eslint-disable-next-line no-unused-vars -OrderRequestBuilder.prototype.buildTotalAmount = function (basket) { - var paymentTransaction = this._getPaymentTransaction(basket); - +OrderRequestBuilder.prototype.buildTotalAmount = function (basket,isCashAppPay) { + var paymentTransaction = this._getPaymentTransaction(basket,isCashAppPay); if (!paymentTransaction) { return null; } diff --git a/cartridges/int_afterpay_core/cartridge/scripts/order/orderService.js b/cartridges/int_afterpay_core/cartridge/scripts/order/orderService.js index 47ebb39..4f3dc44 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/order/orderService.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/order/orderService.js @@ -10,9 +10,9 @@ var OrderRequestBuilder = require('*/cartridge/scripts/order/orderRequestBuilder var requestUrl = null; var requestBody = {}; var orderService = { - generateRequest: function (lineItemCtnr, url) { + generateRequest: function (lineItemCtnr, isCashAppPay) { requestUrl = afterpayUtils.getEndpoint('createOrders'); - this.generateRequestBody(lineItemCtnr, url); + this.generateRequestBody(lineItemCtnr, isCashAppPay); }, getResponse: function () { @@ -22,12 +22,11 @@ var orderService = { return response; }, - generateRequestBody: function (lineItemCtnr, url) { + generateRequestBody: function (lineItemCtnr, isCashAppPay) { var orderRequestBuilder = new OrderRequestBuilder(); - requestBody = orderRequestBuilder.buildRequest({ basket: lineItemCtnr, - url: url, + isCashAppPay: isCashAppPay, requestMethod: 'POST' }).get(); } diff --git a/cartridges/int_afterpay_core/cartridge/scripts/payment/expressCaptureRequestBuilder.js b/cartridges/int_afterpay_core/cartridge/scripts/payment/expressCaptureRequestBuilder.js index 6540487..08a663e 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/payment/expressCaptureRequestBuilder.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/payment/expressCaptureRequestBuilder.js @@ -98,20 +98,19 @@ ExpressCaptureRequestBuilder.prototype.buildItems = function (basket) { var item = new LineItem(); var product = li.product; - // Some lineitems may not be products - // e.g. extended warranties + // Some lineitems may not be products + // e.g. extended warranties if (!product) { item.name = li.getLineItemText(); - item.quantity = li.getQuantity().value; - item.price.amount = 0; - item.price.currency = basket.currencyCode; + item.sku = li.productID; + item.price.currency = li.adjustedNetPrice.currencyCode; } else { - item.name = product.name; - item.sku = product.ID; - item.quantity = li.getQuantity().value; - item.price.amount = product.getPriceModel().getPrice().value; - item.price.currency = product.getPriceModel().getPrice().currencyCode; + item.name = product.name; + item.sku = product.ID; + item.price.currency = product.getPriceModel().getPrice().currencyCode; } + item.quantity = li.getQuantity().value; + item.price.amount = (li.adjustedPrice.value/item.quantity).toString(); return item; }); diff --git a/cartridges/int_afterpay_core/cartridge/scripts/util/afterpaySession.js b/cartridges/int_afterpay_core/cartridge/scripts/util/afterpaySession.js index 3c9071a..f5db081 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/util/afterpaySession.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/util/afterpaySession.js @@ -16,6 +16,7 @@ var AfterpaySession = { session.custom.afterpay_express_checkout_items_checksum = 0; session.custom.afterpay_express_instore_pickup = false; session.custom.afterpay_express_split_shipment = false; + session.custom.is_cashapp = false; }, // Call this whenever the Afterpay Express transaction should be completely cleared clearSession: function () { @@ -30,6 +31,7 @@ var AfterpaySession = { delete session.custom.afterpay_express_checkout_items_checksum; delete session.custom.afterpay_express_instore_pickup; delete session.custom.afterpay_express_split_shipment; + delete session.custom.is_cashapp; }, isValid: function () { return (!empty(session.custom.afterpay_token)); @@ -98,6 +100,12 @@ var AfterpaySession = { return 'token: ' + session.custom.afterpay_token + ' express_checkout: ' + session.custom.afterpay_express_checkout + ' finalize_flow: ' + session.custom.afterpay_express_checkout_finalize_flow + ' checkout_amount: ' + session.custom.afterpay_express_checkout_amount + ' instore_pickup: ' + session.custom.afterpay_express_checkout_amount; + }, + setIsCashAppPay: function (val) { + session.custom.is_cashapp = val; + }, + getIsCashAppPay: function () { + return session.custom.is_cashapp; } }; diff --git a/cartridges/int_afterpay_core/cartridge/scripts/util/afterpayUtilities.js b/cartridges/int_afterpay_core/cartridge/scripts/util/afterpayUtilities.js index 036edeb..215d5aa 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/util/afterpayUtilities.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/util/afterpayUtilities.js @@ -11,12 +11,12 @@ var Locale = require('dw/util/Locale'); */ var sitePreferencesUtilities = { - getRedirectConfirmUrl: function () { - return URLUtils.https('AfterpayRedirect-HandleResponse').toString(); - }, - - getRedirectCancelUrl: function () { - return URLUtils.https('AfterpayRedirect-HandleResponse').toString(); + getRedirectConfirmUrl: function (isCashAppPay) { + if(isCashAppPay){ + return URLUtils.https('CashApp-HandleMobileResponse').toString(); + } else { + return URLUtils.https('AfterpayRedirect-HandleResponse').toString(); + } }, getPaymentMode: function () { @@ -43,6 +43,10 @@ var sitePreferencesUtilities = { return Site.getCurrent().getCustomPreferenceValue('enableAfterpay') || false; }, + isCashAppEnabled: function () { + return Site.getCurrent().getCustomPreferenceValue('enableCashAppPay') && brandUtilities.getCountryCode() == 'US' || false; + }, + getBrandSettings: function () { return JSON.parse(Site.getCurrent().getCustomPreferenceValue('apBrandSettings')); }, @@ -165,17 +169,22 @@ var brandUtilities = { * Checkout Utilities */ var checkoutUtilities = { - getPaymentMethodName: function () { - var brandMapping = require('*/cartridge/scripts/brandMapping'); - var BrandUtilities = brandUtilities; - - var brand = BrandUtilities.getBrand(); - var mapping = brandMapping[brand]; - - if (mapping) { - return mapping.paymentMethod; + getPaymentMethodName: function (isCashAppPay) { + var isCashAppPay = isCashAppPay || false; + if(isCashAppPay) { + return "CASHAPPPAY"; + } else { + var brandMapping = require('*/cartridge/scripts/brandMapping'); + var BrandUtilities = brandUtilities; + + var brand = BrandUtilities.getBrand(); + var mapping = brandMapping[brand]; + + if (mapping) { + return mapping.paymentMethod; + } + return null; } - return null; }, getPaymentMethod: function () { diff --git a/cartridges/int_afterpay_core/cartridge/scripts/util/thresholdUtilities.js b/cartridges/int_afterpay_core/cartridge/scripts/util/thresholdUtilities.js index a709f12..5703d6f 100644 --- a/cartridges/int_afterpay_core/cartridge/scripts/util/thresholdUtilities.js +++ b/cartridges/int_afterpay_core/cartridge/scripts/util/thresholdUtilities.js @@ -78,37 +78,39 @@ var thresholdUtilities = { session.privacy[prefix + 'MaxAmount'] = 0; } }, - checkThreshold: function (price) { + checkThreshold: function (price, isCashAppPay) { + isCashAppPay = isCashAppPay || false; if (afterpayBrand && (price && price.value)) { - result = this.getThresholdResult(price.value); + result = this.getThresholdResult(price.value,isCashAppPay); } return result; }, - checkPriceThreshold: function (price) { + checkPriceThreshold: function (price, isCashAppPay) { + isCashAppPay = isCashAppPay || false; if (afterpayBrand && price) { - result = this.getThresholdResult(price); + result = this.getThresholdResult(price, isCashAppPay); } return result; }, - getThresholdResult: function(price) { + getThresholdResult: function(price, isCashAppPay) { if (price) { var threshold = this.getThresholdAmounts(afterpayBrand); this.saveThresholds(afterpayBrand, threshold); - var paymentMethodName = checkoutUtilities.getPaymentMethodName(); + var paymentMethodName = checkoutUtilities.getPaymentMethodName(isCashAppPay); var paymentMethod; var isApplicable; - if (paymentMethodName) { paymentMethod = PaymentMgr.getPaymentMethod(paymentMethodName); isApplicable = paymentMethod.isApplicable(session.customer, countryCode, price); - result.status = isApplicable; - if (isApplicable) { - result.belowThreshold = price.value <= threshold.minAmount; - result.aboveThreshold = price.value >= threshold.maxAmount; + result.belowThreshold = price <= threshold.minAmount; + result.aboveThreshold = price >= threshold.maxAmount; result.minThresholdAmount = threshold.minAmount; result.maxThresholdAmount = threshold.maxAmount; + if(price >= threshold.minAmount && price <= threshold.maxAmount){ + result.status = true; + } } } } diff --git a/cartridges/int_afterpay_sfra/cartridge/client/default/js/afterpay/customCheckout.js b/cartridges/int_afterpay_sfra/cartridge/client/default/js/afterpay/customCheckout.js index 6c2e0b2..26dee40 100755 --- a/cartridges/int_afterpay_sfra/cartridge/client/default/js/afterpay/customCheckout.js +++ b/cartridges/int_afterpay_sfra/cartridge/client/default/js/afterpay/customCheckout.js @@ -110,6 +110,9 @@ var exports = { let tabelem = document.querySelector('.afterpay-tab') ? document.querySelector('.afterpay-tab') : document.querySelector('.clearpay-tab'); if (window.MutationObserver) { var observer = new MutationObserver(function (mutations) { + if($('.afterpay-tab').hasClass('active') || $('.clearpay-tab').hasClass('active')){ + afterpayExpressWidget.updateExpressWidget(); + } handleStateChange(); }); observer.observe(tabelem, { attributes: true }); diff --git a/cartridges/int_afterpay_sfra/cartridge/client/default/js/cashappCheckout.js b/cartridges/int_afterpay_sfra/cartridge/client/default/js/cashappCheckout.js new file mode 100644 index 0000000..1023038 --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/client/default/js/cashappCheckout.js @@ -0,0 +1,50 @@ +'use strict'; +/* global $ */ +var processInclude = require('base/util'); +function createCashAppToken(){ + var cashappProcessUrl; + if($('.cashapppay-tab').hasClass('active')){ + if($('.form-control.email').val()){ + var cashAppUrl =$('#cashApp-url-createtoken').val() + "?customerEmail=" + $('.form-control.email').val(); + $.ajax({ + type: 'GET', + url: cashAppUrl, + success: function (res) { + if (res.status == 'SUCCESS') { + var afterpaytoken = res.token.apToken; + initCashAppPay(afterpaytoken); + } else { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=FAILED'; + window.location.href = cashappProcessUrl; + } + }, + error: function () { + cashappProcessUrl = $('#cashApp-url-handleerror').val() + '?error=cashapppay.error.token'; + window.location.href = cashappProcessUrl; + } + }); + } else { + cashappProcessUrl = $('#cashApp-url-handleerror').val() + '?error=cashapppay.error.emailmissing'; + window.location.href = cashappProcessUrl; + } + } +} + +$(document).ready(function () { + let cashappelem = document.querySelector('.cashapppay-tab'); + if (cashappelem && window.MutationObserver) { + $('.data-checkout-stage[data-checkout-stage=payment] button.submit-payment').css('display','block'); + $('#cash-app-pay').css('display','none'); + var observer = new MutationObserver(function (mutations) { + if($('.cashapppay-tab').hasClass('active')){ + $.spinner().start(); + createCashAppToken(); + } + }); + observer.observe(cashappelem, { attributes: true }); + } + + $('body').on('checkout:updateCheckoutView', function () { + createCashAppToken(); + }); +}); diff --git a/cartridges/int_afterpay_sfra/cartridge/client/default/js/cashappCheckoutMobile.js b/cartridges/int_afterpay_sfra/cartridge/client/default/js/cashappCheckoutMobile.js new file mode 100644 index 0000000..603b14e --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/client/default/js/cashappCheckoutMobile.js @@ -0,0 +1,34 @@ +'use strict'; +/* global $ */ +function onPageLoad(){ + var cashappProcessUrl; + var cashAppPayListenerOptions = { + onComplete: function(event) { + const { status, cashtag, orderToken} = event.data; + if(event.data){ + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?orderToken=' + event.data.orderToken + '&status=' + event.data.status; + window.location.href = cashappProcessUrl; + } + }, + /* Optional event listeners for merchants to track customer behavior and listen for transaction events in the lifecycle */ + eventListeners: { + "CUSTOMER_REQUEST_DECLINED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=DECLINED'; + window.location.href = cashappProcessUrl; + }, + "CUSTOMER_REQUEST_FAILED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=FAILED'; + window.location.href = cashappProcessUrl; + } + } + } + if(AfterPay != 'undefined'){ + $(".loader-image").fadeOut("slow"); + AfterPay.initializeCashAppPayListeners({countryCode: "US", cashAppPayListenerOptions}); + } +} + +window.onload = function () { + $(".loader-image").fadeOut("slow"); + onPageLoad(); +}; diff --git a/cartridges/int_afterpay_sfra/cartridge/client/default/scss/afterpaystyle.scss b/cartridges/int_afterpay_sfra/cartridge/client/default/scss/afterpaystyle.scss index a70a4e0..2b89d53 100644 --- a/cartridges/int_afterpay_sfra/cartridge/client/default/scss/afterpaystyle.scss +++ b/cartridges/int_afterpay_sfra/cartridge/client/default/scss/afterpaystyle.scss @@ -135,7 +135,7 @@ .redirect-text { text-align: center; margin-top: 2.1875em; - font-size: 1.375em; + font-size: 2.375em; } .checkout-afterpay-message { diff --git a/cartridges/int_afterpay_sfra/cartridge/controllers/AfterpayExpress.js b/cartridges/int_afterpay_sfra/cartridge/controllers/AfterpayExpress.js index e561c4e..740c607 100644 --- a/cartridges/int_afterpay_sfra/cartridge/controllers/AfterpayExpress.js +++ b/cartridges/int_afterpay_sfra/cartridge/controllers/AfterpayExpress.js @@ -35,6 +35,7 @@ function returnJsonError(res, next, err) { } function redirectToErrorDisplay(res, error) { + AfterpaySession.clearSession(); res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', error)); } diff --git a/cartridges/int_afterpay_sfra/cartridge/controllers/AfterpayRedirect.js b/cartridges/int_afterpay_sfra/cartridge/controllers/AfterpayRedirect.js index a843cf6..53a72a8 100644 --- a/cartridges/int_afterpay_sfra/cartridge/controllers/AfterpayRedirect.js +++ b/cartridges/int_afterpay_sfra/cartridge/controllers/AfterpayRedirect.js @@ -206,7 +206,7 @@ server.get('HandleResponse', server.middleware.https, function (req, res, next) productExists = require('*/cartridge/scripts/checkout/afterpayTokenConflict').checkTokenConflict(currentBasket, req.querystring.orderToken); require('*/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus').getPreApprovalResult(currentBasket, req.querystring); if (!productExists || productExists.error) { - res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('apierror.token.conflict', 'afterpay', null))); + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('apierror.flow.invalid', 'afterpay', null))); } else { var order = COHelpers.createOrder(currentBasket); paymentStatusUpdated = require('*/cartridge/scripts/checkout/updatePaymentStatus').handlePaymentStatus(order); diff --git a/cartridges/int_afterpay_sfra/cartridge/controllers/CashApp.js b/cartridges/int_afterpay_sfra/cartridge/controllers/CashApp.js new file mode 100644 index 0000000..e01eafe --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/controllers/CashApp.js @@ -0,0 +1,180 @@ +'use strict'; + +var server = require('server'); +var parsePrice = require('~/cartridge/scripts/util/parsePriceAfterpay.js'); +var Response = require('server/response'); +var URLUtils = require('dw/web/URLUtils'); +var COHelpers = require('*/cartridge/scripts/checkout/checkoutHelpers'); +var AfterpayCOHelpers = require('*/cartridge/scripts/checkout/afterpayCheckoutHelpers'); +var AfterpayRefArchCOHelpers = require('~/cartridge/scripts/checkout/afterpayRefArchCheckoutHelpers'); +var Resource = require('dw/web/Resource'); +let AfterpaySession = require('*/cartridge/scripts/util/afterpaySession'); +let ValidationHelpers = require('*/cartridge/scripts/helpers/basketValidationHelpers'); +var BasketMgr = require('dw/order/BasketMgr'); +var LogUtils = require('*/cartridge/scripts/util/afterpayLogUtils'); +var Logger = LogUtils.getLogger('CashApp'); +var AfterpayShippingHelpers = require('*/cartridge/scripts/checkout/afterpayShippingHelpers'); +var OrderMgr = require('dw/order/OrderMgr'); +var Order = require('dw/order/Order'); +var Money = require('dw/value/Money'); +var Transaction = require('dw/system/Transaction'); +var { + brandUtilities: apBrandUtilities, + checkoutUtilities: apCheckoutUtilities, + sitePreferencesUtilities: sitePreferences +} = require('*/cartridge/scripts/util/afterpayUtilities'); +var thresholdUtilities = require('*/cartridge/scripts/util/thresholdUtilities'); +var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(true); + +function returnJsonError(res, next, err) { + res.json({ + status: 'FAILURE', + error: err, + redirectUrl: URLUtils.url('Cart-Show').toString() + }); + return next(); +} + +server.get('redirectToErrorDisplay', + server.middleware.https, + function (req, res, next) { + var errorMessage = req.querystring.error; + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg(errorMessage, 'afterpay', null))); + next(); +}); + +server.get('CreateToken', + server.middleware.https, + function (req, res, next) { + var OrderModel = require('*/cartridge/models/order'); + var Locale = require('dw/util/Locale'); + var basketCalculationHelpers = require('*/cartridge/scripts/helpers/basketCalculationHelpers'); + var currentBasket = BasketMgr.getCurrentBasket(); + var currentLocale = Locale.getLocale(req.locale.id); + var customerEmail = req.querystring.customerEmail; + + var basketModel = null; + + var validatedProducts = ValidationHelpers.validateProducts(currentBasket); + if (validatedProducts.error) { + return returnJsonError(res, next, 'Problem with basket'); + } + + Transaction.wrap(function () { + currentBasket.setCustomerEmail(customerEmail); + }); + + COHelpers.recalculateBasket(currentBasket); + + basketModel = new OrderModel( + currentBasket, + { usingMultiShipping: false, countryCode: currentLocale.country, containerView: 'basket' } + ); + + let grandTotal = parsePrice(basketModel.totals.grandTotal); + let checkoutPrice = new Money(grandTotal, currentBasket.currencyCode); + var isWithinThreshold = thresholdUtilities.checkThreshold(checkoutPrice,true); + if (!isWithinThreshold.status) { + return returnJsonError(res, next, Resource.msg('cashapppay.error.invalidamount', 'afterpay', null)); + } + // Create the payment instrument + Transaction.wrap(function () { + AfterpayRefArchCOHelpers.removeAllNonGiftCertificatePayments(currentBasket); + currentBasket.createPaymentInstrument(paymentMethodName, checkoutPrice); + }); + + var afterPayTokenResponse = require('*/cartridge/scripts/checkout/afterpayGetToken').getToken(currentBasket,true); + if (afterPayTokenResponse.error) { + return returnJsonError(res, next, Resource.msg('apierror.flow.default', 'afterpay', null)); + } + var orderToken = afterPayTokenResponse.apToken; + if (!orderToken) { + return returnJsonError(res, next, Resource.msg('apierror.flow.default', 'afterpay', null)); + } + AfterpaySession.newSession(orderToken); + AfterpaySession.setItemsChecksum(AfterpayCOHelpers.computeBasketProductLineItemChecksum(currentBasket)); + res.json({ status: 'SUCCESS', token: afterPayTokenResponse }); + return next(); + + +}); + +server.get('HandleResponse', server.middleware.https, function (req, res, next) { + var Order = require('dw/order/Order'); + var orderPlacementStatus; + var paymentStatusUpdated; + var basketValid = false; + var paymentStatus = req.querystring.status; + var currentBasket = BasketMgr.getCurrentBasket(); + switch (paymentStatus) { + case 'SUCCESS': + var itemsChecksum = AfterpayCOHelpers.computeBasketProductLineItemChecksum(currentBasket); + if(AfterpaySession.isValid()){ + if (itemsChecksum == AfterpaySession.getItemsChecksum()) { + basketValid = true; + } + AfterpaySession.clearSession(); + } + if(basketValid){ + var paymentInstrument = currentBasket.getPaymentInstruments(paymentMethodName)[0]; + var paymentTransaction = paymentInstrument.getPaymentTransaction(); + if(paymentTransaction){ + let grandTotal = paymentTransaction.amount.value; + Transaction.wrap(function () { + AfterpayRefArchCOHelpers.removeAllNonGiftCertificatePayments(currentBasket); + currentBasket.createPaymentInstrument(paymentMethodName, new Money(grandTotal, currentBasket.currencyCode)); + }); + } + + require('*/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus').getPreApprovalResult(currentBasket, { status: 'SUCCESS', orderToken: req.querystring.orderToken, isCashAppPay: 'true'}); + var order = COHelpers.createOrder(currentBasket); + paymentStatusUpdated = require('*/cartridge/scripts/checkout/updatePaymentStatus').handlePaymentStatus(order,true); + if (paymentStatusUpdated.authorized) { + Transaction.begin(); + orderPlacementStatus = OrderMgr.placeOrder(order); + Transaction.commit(); + if (!orderPlacementStatus.error) { + Transaction.begin(); + order.setConfirmationStatus(Order.CONFIRMATION_STATUS_CONFIRMED); + order.setExportStatus(Order.EXPORT_STATUS_READY); + Transaction.commit(); + res.redirect(URLUtils.url('Order-Confirm', 'ID', order.orderNo, 'token', order.orderToken)); + } else { + Transaction.wrap(function () { + OrderMgr.failOrder(order, false); + }); + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('order.submission.error', 'afterpay', null))); + } + } else { + Transaction.wrap(function () { + OrderMgr.failOrder(order); + }); + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', paymentStatusUpdated.AfterpayOrderErrorMessage ? paymentStatusUpdated.AfterpayOrderErrorMessage : Resource.msg('apierror.flow.default', 'afterpay', null))); + } + } else { + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('cashapppay.error.missmatch', 'afterpay', null))); + } + + break; + case 'DECLINED': + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('afterpay.api.declined', 'afterpay', null))); + break; + default: + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('apierror.flow.default', 'afterpay', null))); + } + next(); +}); + +server.get('HandleMobileResponse', server.middleware.https, function (req, res, next) { + var cash_request_id = req.querystring.cash_request_id; + if(!empty(cash_request_id)){ + var scriptURL = apBrandUtilities.getBrandSettings().javaScriptUrl; + res.render('checkout/cashAppMobile',{apJavascriptURL: scriptURL}) + } else { + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('afterpay.api.cancelled', 'afterpay', null))); + } + + next(); +}); + +module.exports = server.exports(); diff --git a/cartridges/int_afterpay_sfra/cartridge/controllers/Checkout.js b/cartridges/int_afterpay_sfra/cartridge/controllers/Checkout.js index 1c8567e..6c4810f 100755 --- a/cartridges/int_afterpay_sfra/cartridge/controllers/Checkout.js +++ b/cartridges/int_afterpay_sfra/cartridge/controllers/Checkout.js @@ -25,22 +25,25 @@ server.append( var currentBasket = BasketMgr.getCurrentBasket(); var afterpayErrorResponse = req.querystring.afterpayErrorMessage; var afterpayForm = server.forms.getForm('afterpay'); + var {sitePreferencesUtilities} = require('*/cartridge/scripts/util/afterpayUtilities'); var priceContext; - - priceContext = require('*/cartridge/scripts/util/getTemplateSpecificWidget').getCheckoutWidgetData( - currentBasket, - 'checkout-afterpay-message', - req.locale.id - ); - - res.render('checkout/checkout', { - afterpayApiError: afterpayErrorResponse, - priceContext: priceContext, - customForms: { - afterpayForm: afterpayForm - } - }); - + if(sitePreferencesUtilities.isAfterpayEnabled()){ + priceContext = require('*/cartridge/scripts/util/getTemplateSpecificWidget').getCheckoutWidgetData( + currentBasket, + 'checkout-afterpay-message', + req.locale.id + ); + + res.render('checkout/checkout', { + afterpayApiError: afterpayErrorResponse, + priceContext: priceContext, + customForms: { + afterpayForm: afterpayForm + } + }); + + } + return next(); } ); diff --git a/cartridges/int_afterpay_sfra/cartridge/scripts/checkout/updatePaymentStatus.js b/cartridges/int_afterpay_sfra/cartridge/scripts/checkout/updatePaymentStatus.js index b951092..72f93bd 100644 --- a/cartridges/int_afterpay_sfra/cartridge/scripts/checkout/updatePaymentStatus.js +++ b/cartridges/int_afterpay_sfra/cartridge/scripts/checkout/updatePaymentStatus.js @@ -21,16 +21,16 @@ var updatePaymentStatus = {}; * @param {Object} order - order * @returns {Object} - authorization or error */ -updatePaymentStatus.handlePaymentStatus = function (order) { +updatePaymentStatus.handlePaymentStatus = function (order, isCashAppPay) { var { checkoutUtilities: apCheckoutUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); - var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); var response; var finalPaymentStatus; var errorMessage; var responseCode; var paymentTransaction; var apInitialStatus; - + var isCashAppPay = isCashAppPay || false; + var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(isCashAppPay); var impactOrder = order; if (!paymentMethodName) { @@ -76,7 +76,7 @@ updatePaymentStatus.handlePaymentStatus = function (order) { } } - finalPaymentStatus = require('*/cartridge/scripts/checkout/afterpayHandlePaymentOrder').getPaymentStatus(order, apInitialStatus, expressCheckoutModel); + finalPaymentStatus = require('*/cartridge/scripts/checkout/afterpayHandlePaymentOrder').getPaymentStatus(order, apInitialStatus, expressCheckoutModel, isCashAppPay); response = (finalPaymentStatus.errorMessage) ? finalPaymentStatus.errorMessage : finalPaymentStatus; responseCode = apCheckoutUtilities.getPaymentResponseCode(finalPaymentStatus); diff --git a/cartridges/int_afterpay_sfra/cartridge/scripts/hooks/payment/processor/cashapp_credit.js b/cartridges/int_afterpay_sfra/cartridge/scripts/hooks/payment/processor/cashapp_credit.js new file mode 100644 index 0000000..7f9f9e3 --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/scripts/hooks/payment/processor/cashapp_credit.js @@ -0,0 +1,48 @@ +'use strict'; + +/* API Includes */ +var Transaction = require('dw/system/Transaction'); + +/* Script Modules */ +var collections = require('*/cartridge/scripts/util/collections'); + +/** +* removes other payment instruments from basket and saves afterpay +* @param {Object} basket - basket +* @returns {Object} - errors +*/ +function Handle(basket) { + var currentBasket = basket; + var { checkoutUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); + var paymentMethodName = checkoutUtilities.getPaymentMethodName(true); + + if (!paymentMethodName) { + return { + error: true + }; + } + + Transaction.wrap(function () { + var paymentInstruments = currentBasket.getPaymentInstruments(); + collections.forEach(paymentInstruments, function (item) { + currentBasket.removePaymentInstrument(item); + }); + + currentBasket.createPaymentInstrument( + paymentMethodName, currentBasket.totalGrossPrice + ); + }); + + return { fieldErrors: {}, serverErrors: [], error: false }; +} + +/** + * authorizes the payment processor + * @returns {Object} - errors + */ +function Authorize() { + return { fieldErrors: {}, serverErrors: [], error: false }; +} + +exports.Handle = Handle; +exports.Authorize = Authorize; diff --git a/cartridges/int_afterpay_sfra/cartridge/scripts/logic/services/afterpayUpdateOrderService.js b/cartridges/int_afterpay_sfra/cartridge/scripts/logic/services/afterpayUpdateOrderService.js index d266a12..9a8e058 100644 --- a/cartridges/int_afterpay_sfra/cartridge/scripts/logic/services/afterpayUpdateOrderService.js +++ b/cartridges/int_afterpay_sfra/cartridge/scripts/logic/services/afterpayUpdateOrderService.js @@ -6,10 +6,11 @@ var afterpayUpdateOrderService = module.superModule; afterpayUpdateOrderService.sendConfirmationEmail = function (order, containerView) { var OrderModel = require('*/cartridge/models/order'); var emailHelpers = require('*/cartridge/scripts/helpers/emailHelpers'); + var { brandUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); var orderModel = new OrderModel(order, { containerView: containerView || 'basket', - countryCode: order.getBillingAddress().getCountryCode().value + countryCode: brandUtilities.getCountryCode() }); var orderObject = { order: orderModel }; diff --git a/cartridges/int_afterpay_sfra/cartridge/scripts/util/getTemplateSpecificWidget.js b/cartridges/int_afterpay_sfra/cartridge/scripts/util/getTemplateSpecificWidget.js index 5561cd1..5b0e499 100644 --- a/cartridges/int_afterpay_sfra/cartridge/scripts/util/getTemplateSpecificWidget.js +++ b/cartridges/int_afterpay_sfra/cartridge/scripts/util/getTemplateSpecificWidget.js @@ -4,7 +4,7 @@ var Money = require('dw/value/Money'); /* Script Modules */ -var { brandUtilities: apBrandUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); +var { brandUtilities: apBrandUtilities, sitePreferencesUtilities:apSitePreferences } = require('*/cartridge/scripts/util/afterpayUtilities'); var getTemplateSpecificWidget = {}; @@ -144,6 +144,7 @@ getTemplateSpecificWidget.getCheckoutWidgetData = function (currentBasket, class } var isApplicable = apBrandUtilities.isAfterpayApplicable() && isWithinThreshold.status; + var iscashAppApplicable = apSitePreferences.isCashAppEnabled() && isWithinThreshold.status; var apBrand = apBrandUtilities.getBrand(); if (className === 'checkout-afterpay-message') { @@ -151,6 +152,7 @@ getTemplateSpecificWidget.getCheckoutWidgetData = function (currentBasket, class } priceContext.apApplicable = isApplicable; + priceContext.cashAppApplicable = iscashAppApplicable; priceContext.apBrand = apBrand; return priceContext; diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge.png b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge.png new file mode 100644 index 0000000..062aa7f Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge.png differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge1x.png b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge1x.png new file mode 100644 index 0000000..641dba5 Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge1x.png differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge2x.png b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge2x.png new file mode 100644 index 0000000..0c54392 Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge2x.png differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge3x.png b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge3x.png new file mode 100644 index 0000000..b3aa32a Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapp-badge3x.png differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg new file mode 100644 index 0000000..00eb73c Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark.png b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark.png new file mode 100644 index 0000000..abd315d Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark.png differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark1x.png b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark1x.png new file mode 100644 index 0000000..6ccd20c Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark1x.png differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark2x.png b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark2x.png new file mode 100644 index 0000000..de23c57 Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark2x.png differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark3x.png b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark3x.png new file mode 100644 index 0000000..6ee258e Binary files /dev/null and b/cartridges/int_afterpay_sfra/cartridge/static/default/images/cashapppay-logomark3x.png differ diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpayExpress.js b/cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpayExpress.js index 92d966d..f85e686 100644 --- a/cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpayExpress.js +++ b/cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpayExpress.js @@ -26,8 +26,7 @@ function initAfterpay(settings) { AfterPay.shippingOptionRequired = false; } } - - console.log('onCommenceCheckout(). Actions=', actions); + var afterpayExpressTokenUrl = $('#afterpay-express-url-createtoken').val() + '?s_url=' + encodeURIComponent(window.location.href); // This is to support Afterpay Express from product details page. Add product to cart and checkout. if (productIdSelector && productQuantitySelector) { @@ -35,7 +34,7 @@ function initAfterpay(settings) { let q_elem = document.querySelector(productQuantitySelector); afterpayExpressTokenUrl += '&cartAction=add&pid=' + (p_elem.innerText || '') + '&Quantity=' + (q_elem.value || ''); } - console.log('onCommenceCheckout(). TokenUrl: ', afterpayExpressTokenUrl); + var currentLocation = window.location.href; sleep(commenceDelay).then(() => { $.ajax({ @@ -43,35 +42,29 @@ function initAfterpay(settings) { url: afterpayExpressTokenUrl, success: function (res) { if (res.status == 'SUCCESS') { - console.log('Result of CreateToken: ', res); - // var afterpaytoken = res.response.afterpaytoken; var afterpaytoken = res.token.apToken; - console.log('Got token from afterpay: ', afterpaytoken); actions.resolve(afterpaytoken); } else { alert(res.error); - console.log('Afterpay Express Checkout: Token Creation Failure: ', res.error); actions.reject(AfterPay.CONSTANTS.SERVICE_UNAVAILABLE); } }, error: function () { - console.log('Afterpay Express Checkout: request failure.'); + alert('Afterpay payment failed.'); } }); }); }, error: function () { - console.log('Afterpay Express Checkout: request failure.'); + alert('Afterpay payment failed.'); } }); } }, // NOTE: onShippingAddressChange only needed if shippingOptionRequired is true onShippingAddressChange: function (data, actions) { - console.log('onShippingAddressChange called. data=', data); var shippingMetthodsUrl = $('#afterpay-express-url-getshippingmethods').val(); - console.log('Calling this to get shipping methods: ' + shippingMetthodsUrl); $.ajax({ type: 'POST', url: shippingMetthodsUrl, @@ -87,7 +80,6 @@ function initAfterpay(settings) { phoneNumber: data.phoneNumber }, success: function (response) { - console.log('shipping method computed successfully. Returning data to Afterpay portal via resolve. shippingMethods=', response); // Need to handle case where address is unsupported/invalid if (!response.shipmethods || response.shipmethods.length == 0) { actions.reject(AfterPay.CONSTANTS.SHIPPING_ADDRESS_UNSUPPORTED); @@ -96,19 +88,15 @@ function initAfterpay(settings) { } }, error: function () { - console.log('Afterpay Express Checkout: failure in get shipping methods'); + alert('Afterpay payment failed.'); } }); }, onComplete: function (event) { if (event.data.status == 'SUCCESS') { - console.log('onComplete called with SUCCESS'); - console.log(event.data); var afterpayExpressProcessUrl = $('#afterpay-express-url-processorder').val() + '?orderToken=' + event.data.orderToken + '&merchantReference=' + event.data.merchantReference; $(location).attr('href', afterpayExpressProcessUrl); } else { - console.log('onComplete failed'); - console.log(event.data); var errorUrl = $('#afterpay-express-url-cancelorder').val() + '?orderToken=' + event.data.orderToken + '&merchantReference=' + event.data.merchantReference; $(location).attr('href', errorUrl); } @@ -131,11 +119,10 @@ function reinitializeAfterpayPopup() { url: getCartStatusUrl, success: function (res) { var instorepickup = res.instorepickup; - console.log('Instorepickup setting: ', instorepickup); initAfterpay(instorepickup); }, error: function () { - console.log('Afterpay Express cart status request failure.'); + alert('Afterpay payment failed.'); } }); } diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpayWidget.js b/cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpayWidget.js index 3aa79c1..cb20f15 100644 --- a/cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpayWidget.js +++ b/cartridges/int_afterpay_sfra/cartridge/static/default/js/afterpayWidget.js @@ -6,18 +6,15 @@ function createAfterpayWidget () { target: '#afterpay-widget-container', locale: $('#afterpay-widget-locale').val().replace("_", "-"), onReady: function (event) { - console.log("onReady() called. event=", event); afterpayWidget.update({ - amount: { amount: $('#afterpay-widget-amount').val(), currency: $('#afterpay-widget-currency').val() }, + amount: { amount: $('#afterpay-widget-amount').val(), currency: $('#afterpay-widget-currency').val() } }); $('.afterpay-widget-hideuntilready').css("visibility", "visible"); // Fires when the widget is ready to accept updates. }, onChange: function (event) { - console.log("onChange() called. event=", event.data); if (!event.data.isValid) { let widgetErrorUrl = $('#afterpay-express-url-widgeterror').val() + "?error=" + encodeURIComponent(event.data.error); - console.log("Error with Afterpay Widget: " + event.data.error); window.location.assign(widgetErrorUrl); // Need to clear the session } @@ -25,7 +22,6 @@ function createAfterpayWidget () { // See "Getting the widget's state" for more details. }, onError: function (event) { - console.log("onError() called. event=", event); var errorUrl = $('#afterpay-express-url-cancelorder').val(); $(location).attr('href', errorUrl); // See "Handling widget errors" for more details. @@ -36,7 +32,7 @@ function createAfterpayWidget () { function priceUpdate() { afterpayWidget.update({ - amount: { amount: $('#afterpay-widget-amount').val(), currency: $('#afterpay-widget-currency').val() }, + amount: { amount: $('#afterpay-widget-amount').val(), currency: $('#afterpay-widget-currency').val() } }); } @@ -47,11 +43,8 @@ function checkCartAndUpdateWidget() { url: getCartStatusUrl, success: function(res) { afterpayWidget.update({ - amount: { amount: res.cartTotalAmount.toString(), currency: res.cartTotalCurrency }, + amount: { amount: res.cartTotalAmount.toString(), currency: res.cartTotalCurrency } }); - }, - error: function(){ - console.log("Afterpay Express cart status request failure."); } }); } diff --git a/cartridges/int_afterpay_sfra/cartridge/static/default/js/cashAppWidget.js b/cartridges/int_afterpay_sfra/cartridge/static/default/js/cashAppWidget.js new file mode 100644 index 0000000..442ef66 --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/static/default/js/cashAppWidget.js @@ -0,0 +1,45 @@ +function initCashAppPay(afterpaytoken) { + let commenceDelay = 0; + if(typeof AfterPay != "undefined"){ + var cashappProcessUrl; + $('.data-checkout-stage[data-checkout-stage=payment] button.submit-payment').css('display','none'); + var cashAppPayOptions = { + button: { + size: 'medium', // "medium" | "small" + width: 'full', // "full" | "static" + theme: 'dark', // "dark" | "light" + shape: 'semiround' // "round" | "semiround" + }, + redirectUrl: window.location.href, + onComplete: function(event) { + $.spinner().start(); + if(event.data){ + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?orderToken=' + event.data.orderToken + '&status=' + event.data.status; + window.location.href = cashappProcessUrl; + } + + }, + eventListeners: { + "CUSTOMER_REQUEST_DECLINED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=DECLINED'; + window.location.href = cashappProcessUrl; + }, + "CUSTOMER_REQUEST_FAILED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=FAILED'; + window.location.href = cashappProcessUrl; + } + } + } + } + sleep(commenceDelay).then(() => { + $('#cash-app-pay').css('display','block'); + $.spinner().stop(); + AfterPay.initializeForCashAppPay({countryCode: "US", token: afterpaytoken, cashAppPayOptions}); + }); + +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/cart/checkoutButtons.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/cart/checkoutButtons.isml index 5829aa1..8826d67 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/default/cart/checkoutButtons.isml +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/cart/checkoutButtons.isml @@ -14,7 +14,7 @@ afterpayExpressPickupEnabled - does the current cart and selected ship method in var BrandUtilities = require("*/cartridge/scripts/util/afterpayUtilities.js").brandUtilities; var countrycode = BrandUtilities.getCountryCode(); - var expressCheckoutJS = BrandUtilities.getBrandSettings().javaScriptUrl + "?merchant_key=demo"; + var expressCheckoutJS = BrandUtilities.getBrandSettings().javaScriptUrl; var sitePreferences = require("*/cartridge/scripts/util/afterpayUtilities.js").sitePreferencesUtilities; var afterpayEnabled = sitePreferences.isAfterpayEnabled(); var afterpayExpressCheckoutEnabled = afterpayEnabled ? sitePreferences.isExpressCheckoutEnabled() : false; diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/afterpayTab.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/afterpayTab.isml index bb6c371..505185e 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/afterpayTab.isml +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/afterpayTab.isml @@ -8,4 +8,4 @@ title="${paymentOption.name}" > - \ No newline at end of file + diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppContent.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppContent.isml new file mode 100644 index 0000000..e7c74c9 --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppContent.isml @@ -0,0 +1,3 @@ +
+
diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppSummary.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppSummary.isml new file mode 100644 index 0000000..ad5dc19 --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppSummary.isml @@ -0,0 +1,4 @@ +
+ +
+
diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppTab.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppTab.isml new file mode 100644 index 0000000..afaf472 --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/cashAppTab.isml @@ -0,0 +1,10 @@ + diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsContent.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsContent.isml index adc5c05..3cd7f7a 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsContent.isml +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsContent.isml @@ -5,5 +5,7 @@ + + - \ No newline at end of file + diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsTabs.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsTabs.isml index 0518d39..6ecbd5c 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsTabs.isml +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsTabs.isml @@ -5,5 +5,7 @@ + + - \ No newline at end of file + diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/cashAppMobile.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/cashAppMobile.isml new file mode 100644 index 0000000..606df1e --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/cashAppMobile.isml @@ -0,0 +1,11 @@ + + + + + + +
+
+

${Resource.msg('cashapppay.redirect.notification', 'afterpay', null)}

+

${Resource.msg('redirect.message', 'afterpay', null)}

+
diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/checkout.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/checkout.isml index e8e54fa..b022781 100755 --- a/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/checkout.isml +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/checkout/checkout.isml @@ -7,6 +7,7 @@ var assets = require('*/cartridge/scripts/assets.js'); assets.addJs('/js/checkout.js'); assets.addJs('/js/afterpayCheckout.js'); + assets.addJs('/js/cashappCheckout.js'); assets.addCss('/css/checkout/checkout.css'); assets.addCss('/css/afterpaystyle.css');
@@ -87,6 +88,11 @@
+ +
+ +
+
@@ -107,6 +113,9 @@ + Start of CashAppPay +
+ End of CashAppPay Start of Afterpay ${Resource.msg('clearpay.orderconfirmation.payment.method.name', 'clearpay', null)} + + ${Resource.msg('cashapppay.orderconfirmation.payment.method.name', 'clearpay', null)} + diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/common/scripts.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/common/scripts.isml index 6e30f7b..70eff79 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/default/common/scripts.isml +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/common/scripts.isml @@ -1,5 +1,6 @@ + - \ No newline at end of file + diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/product/components/cashappwidget.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/product/components/cashappwidget.isml new file mode 100644 index 0000000..a842059 --- /dev/null +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/product/components/cashappwidget.isml @@ -0,0 +1,15 @@ + + + var expressCheckoutJS = BrandUtilities.getBrandSettings().javaScriptUrl; + var sitePreferences = require("*/cartridge/scripts/util/afterpayUtilities.js").sitePreferencesUtilities; + var cashAppEnabled = sitePreferences.isCashAppEnabled(); + + + + + + + + + + diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/default/util/afterpayMessage.isml b/cartridges/int_afterpay_sfra/cartridge/templates/default/util/afterpayMessage.isml index 46057bb..dd8223e 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/default/util/afterpayMessage.isml +++ b/cartridges/int_afterpay_sfra/cartridge/templates/default/util/afterpayMessage.isml @@ -28,7 +28,7 @@ rel="noreferrer noopener" href="${require('*/cartridge/scripts/util/afterpayUtilities').brandUtilities.getBrandSettings()['learnMoreUrl']}" > - ${Resource.msg('checkout.content.terms', pdict.brand, null)} + ${Resource.msg('terms.conditions.label', pdict.brand, null)} diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/resources/afterpay.properties b/cartridges/int_afterpay_sfra/cartridge/templates/resources/afterpay.properties index c5839e2..f8499c7 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/resources/afterpay.properties +++ b/cartridges/int_afterpay_sfra/cartridge/templates/resources/afterpay.properties @@ -4,65 +4,49 @@ #log log.filename=afterpay -apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, were happy to help! -apierror.flow.400=Bad Request - Your request is a little wrong -apierror.flow.401=Unauthorized - Your API key is wrong -apierror.flow.402=Afterpay payment declined. Please select an alternative payment method. -apierror.flow.404=Not Found - The specified resource could not be found -apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method -apierror.flow.406=Not Acceptable - You requested a format that isn't json -apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation -apierror.flow.410=Gone - The resource requested has been removed from our servers -apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed +apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, we're happy to help! +apierror.flow.400=Bad Request - Your request is a little wrong. +apierror.flow.401=Unauthorized - Your API key is wrong. +apierror.flow.402=Payment declined. Please select an alternative payment method. +apierror.flow.404=Not Found - The specified resource could not be found. +apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method. +apierror.flow.406=Not Acceptable - You requested a format that isn't json. +apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation. +apierror.flow.410=Gone - The resource requested has been removed from our servers. +apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed. apierror.flow.422=Unprocessable Entity - The request format was valid, however one or more values were incorrect. apierror.flow.429=Too Many Requests - Too many requests may occur if an abnormal number of requests occur. apierror.flow.500=Internal Server Error - We had a problem with our server. Try again later. apierror.flow.503=Service Unavailable - We're temporarily offline for maintenance. Please try again later. apierror.flow.524=A timeout occurred -apierror.token.conflict=Invalid Payment Token‚ something went wrong‚ please try again! -afterpay.invalid.email.error=The Email Address entered contains invalid characters, please review and try again. -order.submission.error=Order cannot be placed because of some error. Please try after sometime. -afterpay.email.invalid.response=consumer.email not a well-formed email address +apierror.flow.invalid=There is an issue placing your Order. Your cart might have been changed. -afterpay.api.pending=Your payment is pending. -afterpay.api.error=An error occurred using Afterpay -afterpay.api.cancelled=Your payment has been cancelled -afterpay.api.declined=Your payment has been declined +afterpay.api.cancelled=Your payment has been cancelled. +afterpay.api.declined=Your payment has been declined. terms.conditions.label=Afterpay Terms & Conditions -payments.label=or make 4 interest-free payments of -learn.more.label=More info -with.label=fortnightly with -copyrights.label= © 2017 Afterpay -terms.link.label=Click here for complete terms. -terms.link.label.us=You must be over 18, a resident of the U.S and meet additional eligibility criteria to qualify. Late fees apply. -terms.link.us=Click here for complete terms. minimum.threshold.message=Afterpay is available for orders over {0} -maximum.threshold.message=The item is unavailable with -payment.tab.label=Installments by -checkout.content.terms=Terms and conditions -checkout.content.redirect.label=You will be redirected to Afterpay when you confirm your order +checkout.content.redirect.label=You will be redirected to Afterpay when you confirm your order. checkout.content.intro.text=Pay in -checkout.first.installment=First payment -checkout.second.installment=Two weeks later -checkout.third.installment=Four weeks later -checkout.fourth.installment=Six weeks later redirect.notification=Redirecting to Afterpay Payment Page. redirect.message=Please wait... -billing.logo=Afterpay -order.guest.email=NA dummy.email.id=test@afterpay.com footer.paymetns=Payments afterpay.orderconfirmation.payment.method.name=Afterpay -expresscheckout.error.multidestination=Afterpay Express Checkout unavailable for your cart (multiple destinations). Please proceed through normal checkout. expresscheckout.error.gettoken=Unable to get token. expresscheckout.error.emptycart=Cart is empty. expresscheckout.error.invalidsession=Invalid session. Please try again. expresscheckout.error.checkout=There was a problem with the Order. Please try again. expresscheckout.error.amountMismatch=Amount returned by Afterpay did not match expected amount. -expresscheckout.error.disabled=Afterpay Express Checkout not enabled. expresscheckout.error.notfinalizeflow=Not in express checkout finalize flow. Please check out again. expresscheckout.error.paymentinvalidsession=Invalid session. Unable to confirm order. -expresscheckout.error.invalidamount=Amount in cart does not qualify for Afterpay checkout +expresscheckout.error.invalidamount=Amount in cart does not qualify for Afterpay checkout. expresscheckout.error.missingchecksum=No widget checksum + +cashapppay.orderconfirmation.payment.method.name=Cash App +cashapppay.error.emailmissing=Please Enter Your Email-ID. +cashapppay.error.missmatch=The items in the cart does not match the Cash App Pay order items. +cashapppay.error.invalidamount=Amount in cart does not qualify for Cash App Pay checkout. +cashapppay.error.token=Cash App is having a problem with the order. Please select an alternative payment method. +cashapppay.redirect.notification=Processing your payment. diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay.properties b/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay.properties index c5e2471..c7f8724 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay.properties +++ b/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay.properties @@ -2,66 +2,43 @@ # PLP/PDP message ############################################## #log -log.filename=afterpay +log.filename=clearpay -apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, were happy to help! -apierror.flow.400=Bad Request - Your request is a little wrong -apierror.flow.401=Unauthorized - Your API key is wrong +apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, we're happy to help! +apierror.flow.400=Bad Request - Your request is a little wrong. +apierror.flow.401=Unauthorized - Your API key is wrong. apierror.flow.402=Clearpay payment declined. Please select an alternative payment method. -apierror.flow.404=Not Found - The specified resource could not be found -apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method -apierror.flow.406=Not Acceptable - You requested a format that isn't json -apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation -apierror.flow.410=Gone - The resource requested has been removed from our servers -apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed +apierror.flow.404=Not Found - The specified resource could not be found. +apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method. +apierror.flow.406=Not Acceptable - You requested a format that isn't json. +apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation. +apierror.flow.410=Gone - The resource requested has been removed from our servers. +apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed. apierror.flow.422=Unprocessable Entity - The request format was valid, however one or more values were incorrect. apierror.flow.429=Too Many Requests - Too many requests may occur if an abnormal number of requests occur. apierror.flow.500=Internal Server Error - We had a problem with our server. Try again later. apierror.flow.503=Service Unavailable - We're temporarily offline for maintenance. Please try again later. apierror.flow.524=A timeout occurred -apierror.token.conflict=Invalid Payment Token‚ something went wrong‚ please try again! -afterpay.invalid.email.error=The Email Address entered contains invalid characters, please review and try again. -order.submission.error=Order cannot be placed because of some error. Please try after sometime. -afterpay.email.invalid.response=consumer.email not a well-formed email address +apierror.flow.invalid=There is an issue placing your Order. Your cart might have been changed. -afterpay.api.pending=Your payment is pending. -afterpay.api.error=An error occurred using Clearpay -afterpay.api.cancelled=Your payment has been cancelled -afterpay.api.declined=Your payment has been declined +afterpay.api.cancelled=Your payment has been cancelled. +afterpay.api.declined=Your payment has been declined. terms.conditions.label=Clearpay Terms & Conditions -payments.label=or make 4 interest-free payments of -learn.more.label=More info -with.label= fortnightly with -copyrights.label= © 2017 Clearpay -terms.link.label=Click here for complete terms. -terms.link.label.us=You must be over 18, a resident of the U.S and meet additional eligibility criteria to qualify. Late fees apply. -terms.link.us=Click here for complete terms. minimum.threshold.message=Clearpay is available for orders over {0} -maximum.threshold.message=The item is unavailable with -payment.tab.label=Installments by -checkout.content.terms=Terms and conditions -checkout.content.redirect.label=You will be redirected to Clearpay when you confirm your order +checkout.content.redirect.label=You will be redirected to Clearpay when you confirm your order. checkout.content.intro.text=Pay in -checkout.first.installment=First payment -checkout.second.installment=Two weeks later -checkout.third.installment=Four weeks later -checkout.fourth.installment=Six weeks later redirect.notification=Redirecting to Clearpay Payment Page. redirect.message=Please wait... -billing.logo=Clearpay -order.guest.email=NA dummy.email.id=test@clearpay.com clearpay.orderconfirmation.payment.method.name=Clearpay -expresscheckout.error.multidestination=Clearpay Express Checkout unavailable for your cart (multiple destinations). Please proceed through normal checkout. expresscheckout.error.gettoken=Unable to get token. expresscheckout.error.emptycart=Cart is empty. expresscheckout.error.invalidsession=Invalid session. Please try again. expresscheckout.error.checkout=There was a problem with the Order. Please try again. -expresscheckout.error.amountMismatch=Amount returned by Afterpay did not match expected amount. -expresscheckout.error.disabled=Clearpay Express Checkout not enabled. +expresscheckout.error.amountMismatch=Amount returned by Clearpay did not match expected amount. expresscheckout.error.notfinalizeflow=Not in express checkout finalize flow. Please check out again. expresscheckout.error.paymentinvalidsession=Invalid session. Unable to confirm order. -expresscheckout.error.invalidamount=Amount in cart does not qualify for Clearpay checkout +expresscheckout.error.invalidamount=Amount in cart does not qualify for Clearpay checkout. expresscheckout.error.missingchecksum=No widget checksum diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_es_ES.properties b/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_es_ES.properties index 9f34ecd..7ec929c 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_es_ES.properties +++ b/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_es_ES.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Términos y condiciones -checkout.content.redirect.label=Serás redirigido a la plataforma de Clearpay para completar tu información de pago. -checkout.content.intro.text=Paga en \ No newline at end of file +apierror.flow.default=¡Uy! Parece que ha habido un problema. Si el error persiste, por favor háznoslo saber, ¡estaremos encantados de ayudarte! +apierror.flow.402=El pago con Clearpay ha sido rechazado. Por favor selecciona un método de pago alternativo +redirect.notification=Redirigiendo a la página de pago de Clearpay +redirect.message=Por favor, espera +terms.conditions.label=Términos y condiciones de Clearpay +checkout.content.redirect.label=Serás redirigido a Clearpay cuando confirmes el pedido +checkout.content.intro.text=Paga en +minimum.threshold.message=Clearpay está disponible para pedidos superiores a {0} +afterpay.api.declined=Tu pago ha sido rechazado +afterpay.api.cancelled=Tu pago ha sido cancelado diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_fr_FR.properties b/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_fr_FR.properties index 1ac8f22..1b9483f 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_fr_FR.properties +++ b/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_fr_FR.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Conditions générales +apierror.flow.default=Oops! On dirait qu’on a eu un probleme. Si le probleme persiste, veuillez nous en informer, nous serons ravis de vous aider +apierror.flow.402=Paiement Clearpay refusé. Merci de sélectionner un mode de paiement alternatif +redirect.notification=Redirection vers la page de paiement de Clearpay +redirect.message=S.V.P attendre... +terms.conditions.label=Termes et conditions Clearpay checkout.content.redirect.label=Vous allez être redirigé vers Clearpay pour renseigner vos informations de paiement. -checkout.content.intro.text=Payez en \ No newline at end of file +checkout.content.intro.text=Payez en +minimum.threshold.message=Clearpay est disponible pour les commandes supérieures a {0} +afterpay.api.declined=Votre paiement a été refusé +afterpay.api.cancelled=Votre paiement a été annulé diff --git a/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_it_IT.properties b/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_it_IT.properties index 2da0c31..e429393 100644 --- a/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_it_IT.properties +++ b/cartridges/int_afterpay_sfra/cartridge/templates/resources/clearpay_it_IT.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Termini&Condizioni +apierror.flow.default=Ops! Sembra che abbiamo avuto un problema. Se il problema persiste, faccelo sapere, saremo felici di aiutarti +apierror.flow.402=Il pagamento Clearpay rifiuta. Seleziona un metodo di pagamento alternativo +redirect.message=Attendere prego... +redirect.notification=Reindirizzamento alla pagina di pagamento Clearpay +terms.conditions.label=Termini e condizioni Clearpay checkout.content.redirect.label=Verrai reindirizzato alla piattaforma Clearpay per completare il modulo con le informazioni relative al pagamento. -checkout.content.intro.text=Paga in \ No newline at end of file +checkout.content.intro.text=Paga in +minimum.threshold.message=Clearpay e disponibile per ordini superiori {0} +afterpay.api.declined=Il tuo pagamento è stato rifiutato +afterpay.api.cancelled=Il tuo pagamento è stato annullato diff --git a/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/afterpay/customCheckout.js b/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/afterpay/customCheckout.js index 6a1115c..450647d 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/afterpay/customCheckout.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/afterpay/customCheckout.js @@ -112,6 +112,9 @@ var exports = { let tabelem = document.querySelector('.afterpay-tab') ? document.querySelector('.afterpay-tab') : document.querySelector('.clearpay-tab'); if (window.MutationObserver) { var observer = new MutationObserver(function (mutations) { + if($('.afterpay-tab').hasClass('active') || $('.clearpay-tab').hasClass('active')){ + afterpayExpressWidget.updateExpressWidget(); + } handleStateChange(); }); observer.observe(tabelem, { attributes: true }); diff --git a/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/cashappCheckout.js b/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/cashappCheckout.js new file mode 100644 index 0000000..1a201c7 --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/cashappCheckout.js @@ -0,0 +1,45 @@ +'use strict'; +/* global $ */ +var processInclude = require('base/util'); +function createCashAppToken(){ + var cashappProcessUrl; + if($('.cashapppay-tab').hasClass('active')){ + var cashAppUrl = $('#cashApp-url-createtoken').val(); + $.ajax({ + type: 'GET', + url: cashAppUrl, + success: function (res) { + if (res.status == 'SUCCESS') { + var afterpaytoken = res.token.apToken; + initCashAppPay(afterpaytoken); + } else { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=FAILED'; + window.location.href = cashappProcessUrl; + } + }, + error: function () { + cashappProcessUrl = $('#cashApp-url-handleerror').val() + '?error=cashapppay.error.token'; + window.location.href = cashappProcessUrl; + } + }); + } +} + +$(document).ready(function () { + let cashappelem = document.querySelector('.cashapppay-tab'); + if (cashappelem && window.MutationObserver) { + var observer = new MutationObserver(function (mutations) { + $('.data-checkout-stage[data-checkout-stage=payment] button.submit-payment').css('display','block'); + $('#cash-app-pay').css('display','none'); + if($('.cashapppay-tab').hasClass('active')){ + $.spinner().start(); + createCashAppToken(); + } + }); + observer.observe(cashappelem, { attributes: true }); + } + + $('body').on('checkout:updateCheckoutView', function () { + createCashAppToken(); + }); +}); diff --git a/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/cashappCheckoutMobile.js b/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/cashappCheckoutMobile.js new file mode 100644 index 0000000..603b14e --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/cashappCheckoutMobile.js @@ -0,0 +1,34 @@ +'use strict'; +/* global $ */ +function onPageLoad(){ + var cashappProcessUrl; + var cashAppPayListenerOptions = { + onComplete: function(event) { + const { status, cashtag, orderToken} = event.data; + if(event.data){ + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?orderToken=' + event.data.orderToken + '&status=' + event.data.status; + window.location.href = cashappProcessUrl; + } + }, + /* Optional event listeners for merchants to track customer behavior and listen for transaction events in the lifecycle */ + eventListeners: { + "CUSTOMER_REQUEST_DECLINED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=DECLINED'; + window.location.href = cashappProcessUrl; + }, + "CUSTOMER_REQUEST_FAILED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=FAILED'; + window.location.href = cashappProcessUrl; + } + } + } + if(AfterPay != 'undefined'){ + $(".loader-image").fadeOut("slow"); + AfterPay.initializeCashAppPayListeners({countryCode: "US", cashAppPayListenerOptions}); + } +} + +window.onload = function () { + $(".loader-image").fadeOut("slow"); + onPageLoad(); +}; diff --git a/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/checkout/checkout.js b/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/checkout/checkout.js index cf0fd86..8f18cbc 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/checkout/checkout.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/client/default/js/checkout/checkout.js @@ -360,7 +360,6 @@ var scrollAnimate = require('base/components/scrollAnimate'); defer.reject(data); } } else { - console.log(data.continueUrl); var redirect = $('
') .appendTo(document.body) .attr({ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/client/default/scss/afterpaystyle.scss b/cartridges/int_afterpay_sfra_6/cartridge/client/default/scss/afterpaystyle.scss index a70a4e0..2b89d53 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/client/default/scss/afterpaystyle.scss +++ b/cartridges/int_afterpay_sfra_6/cartridge/client/default/scss/afterpaystyle.scss @@ -135,7 +135,7 @@ .redirect-text { text-align: center; margin-top: 2.1875em; - font-size: 1.375em; + font-size: 2.375em; } .checkout-afterpay-message { diff --git a/cartridges/int_afterpay_sfra_6/cartridge/controllers/AfterpayExpress.js b/cartridges/int_afterpay_sfra_6/cartridge/controllers/AfterpayExpress.js index 08c9286..283eac4 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/controllers/AfterpayExpress.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/controllers/AfterpayExpress.js @@ -35,6 +35,7 @@ function returnJsonError(res, next, err) { } function redirectToErrorDisplay(res, error) { + AfterpaySession.clearSession(); res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', error)); } diff --git a/cartridges/int_afterpay_sfra_6/cartridge/controllers/AfterpayRedirect.js b/cartridges/int_afterpay_sfra_6/cartridge/controllers/AfterpayRedirect.js index b92f6fc..8a8353c 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/controllers/AfterpayRedirect.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/controllers/AfterpayRedirect.js @@ -206,7 +206,7 @@ server.get('HandleResponse', server.middleware.https, function (req, res, next) productExists = require('*/cartridge/scripts/checkout/afterpayTokenConflict').checkTokenConflict(currentBasket, req.querystring.orderToken); require('*/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus').getPreApprovalResult(currentBasket, req.querystring); if (!productExists || productExists.error) { - res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('apierror.token.conflict', 'afterpay', null))); + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('apierror.flow.invalid', 'afterpay', null))); } else { var order = COHelpers.createOrder(currentBasket); paymentStatusUpdated = require('*/cartridge/scripts/checkout/updatePaymentStatus').handlePaymentStatus(order); diff --git a/cartridges/int_afterpay_sfra_6/cartridge/controllers/CashApp.js b/cartridges/int_afterpay_sfra_6/cartridge/controllers/CashApp.js new file mode 100644 index 0000000..11f1a49 --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/controllers/CashApp.js @@ -0,0 +1,179 @@ +'use strict'; + +var server = require('server'); +var parsePrice = require('~/cartridge/scripts/util/parsePriceAfterpay.js'); +var Response = require('server/response'); +var URLUtils = require('dw/web/URLUtils'); +var COHelpers = require('*/cartridge/scripts/checkout/checkoutHelpers'); +var AfterpayCOHelpers = require('*/cartridge/scripts/checkout/afterpayCheckoutHelpers'); +var AfterpayRefArchCOHelpers = require('~/cartridge/scripts/checkout/afterpayRefArchCheckoutHelpers'); +var Resource = require('dw/web/Resource'); +let AfterpaySession = require('*/cartridge/scripts/util/afterpaySession'); +let ValidationHelpers = require('*/cartridge/scripts/helpers/basketValidationHelpers'); +var BasketMgr = require('dw/order/BasketMgr'); +var LogUtils = require('*/cartridge/scripts/util/afterpayLogUtils'); +var Logger = LogUtils.getLogger('CashApp'); +var AfterpayShippingHelpers = require('*/cartridge/scripts/checkout/afterpayShippingHelpers'); +var OrderMgr = require('dw/order/OrderMgr'); +var Order = require('dw/order/Order'); +var Money = require('dw/value/Money'); +var Transaction = require('dw/system/Transaction'); +var { + brandUtilities: apBrandUtilities, + checkoutUtilities: apCheckoutUtilities, + sitePreferencesUtilities: sitePreferences +} = require('*/cartridge/scripts/util/afterpayUtilities'); +var thresholdUtilities = require('*/cartridge/scripts/util/thresholdUtilities'); +var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(true); + +function returnJsonError(res, next, err) { + res.json({ + status: 'FAILURE', + error: err, + redirectUrl: URLUtils.url('Cart-Show').toString() + }); + return next(); +} + +server.get('redirectToErrorDisplay', + server.middleware.https, + function (req, res, next) { + var errorMessage = req.querystring.error; + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg(errorMessage, 'afterpay', null))); + next(); +}); + +server.get('CreateToken', + server.middleware.https, + function (req, res, next) { + var OrderModel = require('*/cartridge/models/order'); + var Locale = require('dw/util/Locale'); + var basketCalculationHelpers = require('*/cartridge/scripts/helpers/basketCalculationHelpers'); + var currentBasket = BasketMgr.getCurrentBasket(); + var currentLocale = Locale.getLocale(req.locale.id); + + var basketModel = null; + + var validatedProducts = ValidationHelpers.validateProducts(currentBasket); + if (validatedProducts.error) { + return returnJsonError(res, next, 'Problem with basket'); + } + + COHelpers.recalculateBasket(currentBasket); + + basketModel = new OrderModel( + currentBasket, + { usingMultiShipping: false, countryCode: currentLocale.country, containerView: 'basket' } + ); + + let grandTotal = parsePrice(basketModel.totals.grandTotal); + let checkoutPrice = new Money(grandTotal, currentBasket.currencyCode); + var isWithinThreshold = thresholdUtilities.checkThreshold(checkoutPrice,true); + if (!isWithinThreshold.status) { + return returnJsonError(res, next, Resource.msg('cashapppay.error.invalidamount', 'afterpay', null)); + } + // Create the payment instrument + Transaction.wrap(function () { + AfterpayRefArchCOHelpers.removeAllNonGiftCertificatePayments(currentBasket); + currentBasket.createPaymentInstrument(paymentMethodName, checkoutPrice); + }); + + var afterPayTokenResponse = require('*/cartridge/scripts/checkout/afterpayGetToken').getToken(currentBasket,true); + if (afterPayTokenResponse.error) { + return returnJsonError(res, next, Resource.msg('apierror.flow.default', 'afterpay', null)); + } + var orderToken = afterPayTokenResponse.apToken; + if (!orderToken) { + return returnJsonError(res, next, Resource.msg('apierror.flow.default', 'afterpay', null)); + } + AfterpaySession.newSession(orderToken); + AfterpaySession.setItemsChecksum(AfterpayCOHelpers.computeBasketProductLineItemChecksum(currentBasket)); + res.json({ status: 'SUCCESS', token: afterPayTokenResponse }); + return next(); + + +}); + +server.get('HandleResponse', server.middleware.https, function (req, res, next) { + var Order = require('dw/order/Order'); + var orderPlacementStatus; + var paymentStatusUpdated; + var basketValid = false; + var paymentStatus = req.querystring.status; + var currentBasket = BasketMgr.getCurrentBasket(); + switch (paymentStatus) { + case 'SUCCESS': + var itemsChecksum = AfterpayCOHelpers.computeBasketProductLineItemChecksum(currentBasket); + if(AfterpaySession.isValid()){ + if (itemsChecksum == AfterpaySession.getItemsChecksum()) { + basketValid = true; + } + AfterpaySession.clearSession(); + } + if(basketValid){ + var paymentInstrument = currentBasket.getPaymentInstruments(paymentMethodName)[0]; + var paymentTransaction = paymentInstrument.getPaymentTransaction(); + if(paymentTransaction){ + let grandTotal = paymentTransaction.amount.value; + Transaction.wrap(function () { + AfterpayRefArchCOHelpers.removeAllNonGiftCertificatePayments(currentBasket); + currentBasket.createPaymentInstrument(paymentMethodName, new Money(grandTotal, currentBasket.currencyCode)); + }); + } + + require('*/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus').getPreApprovalResult(currentBasket, { status: 'SUCCESS', orderToken: req.querystring.orderToken, isCashAppPay: 'true'}); + var order = COHelpers.createOrder(currentBasket); + paymentStatusUpdated = require('*/cartridge/scripts/checkout/updatePaymentStatus').handlePaymentStatus(order,true); + if (paymentStatusUpdated.authorized) { + Transaction.begin(); + orderPlacementStatus = OrderMgr.placeOrder(order); + Transaction.commit(); + if (!orderPlacementStatus.error) { + Transaction.begin(); + order.setConfirmationStatus(Order.CONFIRMATION_STATUS_CONFIRMED); + order.setExportStatus(Order.EXPORT_STATUS_READY); + Transaction.commit(); + res.render('checkout/confirmOrder', { + orderID: order.orderNo, + orderToken: order.orderToken, + continueUrl: URLUtils.url('Order-Confirm').toString() + }); + } else { + Transaction.wrap(function () { + OrderMgr.failOrder(order, false); + }); + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('order.submission.error', 'afterpay', null))); + } + } else { + Transaction.wrap(function () { + OrderMgr.failOrder(order); + }); + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', paymentStatusUpdated.AfterpayOrderErrorMessage ? paymentStatusUpdated.AfterpayOrderErrorMessage : Resource.msg('apierror.flow.default', 'afterpay', null))); + } + } else { + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('cashapppay.error.missmatch', 'afterpay', null))); + } + + break; + case 'DECLINED': + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('afterpay.api.declined', 'afterpay', null))); + break; + default: + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('apierror.flow.default', 'afterpay', null))); + } + next(); +}); + +server.get('HandleMobileResponse', server.middleware.https, function (req, res, next) { + var cash_request_id = req.querystring.cash_request_id; + if(!empty(cash_request_id)){ + var scriptURL = apBrandUtilities.getBrandSettings().javaScriptUrl; + res.render('checkout/cashAppMobile',{apJavascriptURL: scriptURL}) + } else { + res.redirect(URLUtils.url('Checkout-Begin', 'stage', 'payment', 'afterpayErrorMessage', Resource.msg('afterpay.api.cancelled', 'afterpay', null))); + } + + next(); +}); + +module.exports = server.exports(); diff --git a/cartridges/int_afterpay_sfra_6/cartridge/controllers/Checkout.js b/cartridges/int_afterpay_sfra_6/cartridge/controllers/Checkout.js index 1c8567e..6c4810f 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/controllers/Checkout.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/controllers/Checkout.js @@ -25,22 +25,25 @@ server.append( var currentBasket = BasketMgr.getCurrentBasket(); var afterpayErrorResponse = req.querystring.afterpayErrorMessage; var afterpayForm = server.forms.getForm('afterpay'); + var {sitePreferencesUtilities} = require('*/cartridge/scripts/util/afterpayUtilities'); var priceContext; - - priceContext = require('*/cartridge/scripts/util/getTemplateSpecificWidget').getCheckoutWidgetData( - currentBasket, - 'checkout-afterpay-message', - req.locale.id - ); - - res.render('checkout/checkout', { - afterpayApiError: afterpayErrorResponse, - priceContext: priceContext, - customForms: { - afterpayForm: afterpayForm - } - }); - + if(sitePreferencesUtilities.isAfterpayEnabled()){ + priceContext = require('*/cartridge/scripts/util/getTemplateSpecificWidget').getCheckoutWidgetData( + currentBasket, + 'checkout-afterpay-message', + req.locale.id + ); + + res.render('checkout/checkout', { + afterpayApiError: afterpayErrorResponse, + priceContext: priceContext, + customForms: { + afterpayForm: afterpayForm + } + }); + + } + return next(); } ); diff --git a/cartridges/int_afterpay_sfra_6/cartridge/scripts/checkout/updatePaymentStatus.js b/cartridges/int_afterpay_sfra_6/cartridge/scripts/checkout/updatePaymentStatus.js index b951092..72f93bd 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/scripts/checkout/updatePaymentStatus.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/scripts/checkout/updatePaymentStatus.js @@ -21,16 +21,16 @@ var updatePaymentStatus = {}; * @param {Object} order - order * @returns {Object} - authorization or error */ -updatePaymentStatus.handlePaymentStatus = function (order) { +updatePaymentStatus.handlePaymentStatus = function (order, isCashAppPay) { var { checkoutUtilities: apCheckoutUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); - var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); var response; var finalPaymentStatus; var errorMessage; var responseCode; var paymentTransaction; var apInitialStatus; - + var isCashAppPay = isCashAppPay || false; + var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(isCashAppPay); var impactOrder = order; if (!paymentMethodName) { @@ -76,7 +76,7 @@ updatePaymentStatus.handlePaymentStatus = function (order) { } } - finalPaymentStatus = require('*/cartridge/scripts/checkout/afterpayHandlePaymentOrder').getPaymentStatus(order, apInitialStatus, expressCheckoutModel); + finalPaymentStatus = require('*/cartridge/scripts/checkout/afterpayHandlePaymentOrder').getPaymentStatus(order, apInitialStatus, expressCheckoutModel, isCashAppPay); response = (finalPaymentStatus.errorMessage) ? finalPaymentStatus.errorMessage : finalPaymentStatus; responseCode = apCheckoutUtilities.getPaymentResponseCode(finalPaymentStatus); diff --git a/cartridges/int_afterpay_sfra_6/cartridge/scripts/hooks/payment/processor/cashapp_credit.js b/cartridges/int_afterpay_sfra_6/cartridge/scripts/hooks/payment/processor/cashapp_credit.js new file mode 100644 index 0000000..7f9f9e3 --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/scripts/hooks/payment/processor/cashapp_credit.js @@ -0,0 +1,48 @@ +'use strict'; + +/* API Includes */ +var Transaction = require('dw/system/Transaction'); + +/* Script Modules */ +var collections = require('*/cartridge/scripts/util/collections'); + +/** +* removes other payment instruments from basket and saves afterpay +* @param {Object} basket - basket +* @returns {Object} - errors +*/ +function Handle(basket) { + var currentBasket = basket; + var { checkoutUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); + var paymentMethodName = checkoutUtilities.getPaymentMethodName(true); + + if (!paymentMethodName) { + return { + error: true + }; + } + + Transaction.wrap(function () { + var paymentInstruments = currentBasket.getPaymentInstruments(); + collections.forEach(paymentInstruments, function (item) { + currentBasket.removePaymentInstrument(item); + }); + + currentBasket.createPaymentInstrument( + paymentMethodName, currentBasket.totalGrossPrice + ); + }); + + return { fieldErrors: {}, serverErrors: [], error: false }; +} + +/** + * authorizes the payment processor + * @returns {Object} - errors + */ +function Authorize() { + return { fieldErrors: {}, serverErrors: [], error: false }; +} + +exports.Handle = Handle; +exports.Authorize = Authorize; diff --git a/cartridges/int_afterpay_sfra_6/cartridge/scripts/logic/services/afterpayUpdateOrderService.js b/cartridges/int_afterpay_sfra_6/cartridge/scripts/logic/services/afterpayUpdateOrderService.js index d266a12..9a8e058 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/scripts/logic/services/afterpayUpdateOrderService.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/scripts/logic/services/afterpayUpdateOrderService.js @@ -6,10 +6,11 @@ var afterpayUpdateOrderService = module.superModule; afterpayUpdateOrderService.sendConfirmationEmail = function (order, containerView) { var OrderModel = require('*/cartridge/models/order'); var emailHelpers = require('*/cartridge/scripts/helpers/emailHelpers'); + var { brandUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); var orderModel = new OrderModel(order, { containerView: containerView || 'basket', - countryCode: order.getBillingAddress().getCountryCode().value + countryCode: brandUtilities.getCountryCode() }); var orderObject = { order: orderModel }; diff --git a/cartridges/int_afterpay_sfra_6/cartridge/scripts/util/getTemplateSpecificWidget.js b/cartridges/int_afterpay_sfra_6/cartridge/scripts/util/getTemplateSpecificWidget.js index 5561cd1..5b0e499 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/scripts/util/getTemplateSpecificWidget.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/scripts/util/getTemplateSpecificWidget.js @@ -4,7 +4,7 @@ var Money = require('dw/value/Money'); /* Script Modules */ -var { brandUtilities: apBrandUtilities } = require('*/cartridge/scripts/util/afterpayUtilities'); +var { brandUtilities: apBrandUtilities, sitePreferencesUtilities:apSitePreferences } = require('*/cartridge/scripts/util/afterpayUtilities'); var getTemplateSpecificWidget = {}; @@ -144,6 +144,7 @@ getTemplateSpecificWidget.getCheckoutWidgetData = function (currentBasket, class } var isApplicable = apBrandUtilities.isAfterpayApplicable() && isWithinThreshold.status; + var iscashAppApplicable = apSitePreferences.isCashAppEnabled() && isWithinThreshold.status; var apBrand = apBrandUtilities.getBrand(); if (className === 'checkout-afterpay-message') { @@ -151,6 +152,7 @@ getTemplateSpecificWidget.getCheckoutWidgetData = function (currentBasket, class } priceContext.apApplicable = isApplicable; + priceContext.cashAppApplicable = iscashAppApplicable; priceContext.apBrand = apBrand; return priceContext; diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge.png b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge.png new file mode 100644 index 0000000..062aa7f Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge.png differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge1x.png b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge1x.png new file mode 100644 index 0000000..641dba5 Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge1x.png differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge2x.png b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge2x.png new file mode 100644 index 0000000..0c54392 Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge2x.png differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge3x.png b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge3x.png new file mode 100644 index 0000000..b3aa32a Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapp-badge3x.png differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg new file mode 100644 index 0000000..00eb73c Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark.png b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark.png new file mode 100644 index 0000000..abd315d Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark.png differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark1x.png b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark1x.png new file mode 100644 index 0000000..6ccd20c Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark1x.png differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark2x.png b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark2x.png new file mode 100644 index 0000000..de23c57 Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark2x.png differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark3x.png b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark3x.png new file mode 100644 index 0000000..6ee258e Binary files /dev/null and b/cartridges/int_afterpay_sfra_6/cartridge/static/default/images/cashapppay-logomark3x.png differ diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/afterpayExpress.js b/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/afterpayExpress.js index 92d966d..f85e686 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/afterpayExpress.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/afterpayExpress.js @@ -26,8 +26,7 @@ function initAfterpay(settings) { AfterPay.shippingOptionRequired = false; } } - - console.log('onCommenceCheckout(). Actions=', actions); + var afterpayExpressTokenUrl = $('#afterpay-express-url-createtoken').val() + '?s_url=' + encodeURIComponent(window.location.href); // This is to support Afterpay Express from product details page. Add product to cart and checkout. if (productIdSelector && productQuantitySelector) { @@ -35,7 +34,7 @@ function initAfterpay(settings) { let q_elem = document.querySelector(productQuantitySelector); afterpayExpressTokenUrl += '&cartAction=add&pid=' + (p_elem.innerText || '') + '&Quantity=' + (q_elem.value || ''); } - console.log('onCommenceCheckout(). TokenUrl: ', afterpayExpressTokenUrl); + var currentLocation = window.location.href; sleep(commenceDelay).then(() => { $.ajax({ @@ -43,35 +42,29 @@ function initAfterpay(settings) { url: afterpayExpressTokenUrl, success: function (res) { if (res.status == 'SUCCESS') { - console.log('Result of CreateToken: ', res); - // var afterpaytoken = res.response.afterpaytoken; var afterpaytoken = res.token.apToken; - console.log('Got token from afterpay: ', afterpaytoken); actions.resolve(afterpaytoken); } else { alert(res.error); - console.log('Afterpay Express Checkout: Token Creation Failure: ', res.error); actions.reject(AfterPay.CONSTANTS.SERVICE_UNAVAILABLE); } }, error: function () { - console.log('Afterpay Express Checkout: request failure.'); + alert('Afterpay payment failed.'); } }); }); }, error: function () { - console.log('Afterpay Express Checkout: request failure.'); + alert('Afterpay payment failed.'); } }); } }, // NOTE: onShippingAddressChange only needed if shippingOptionRequired is true onShippingAddressChange: function (data, actions) { - console.log('onShippingAddressChange called. data=', data); var shippingMetthodsUrl = $('#afterpay-express-url-getshippingmethods').val(); - console.log('Calling this to get shipping methods: ' + shippingMetthodsUrl); $.ajax({ type: 'POST', url: shippingMetthodsUrl, @@ -87,7 +80,6 @@ function initAfterpay(settings) { phoneNumber: data.phoneNumber }, success: function (response) { - console.log('shipping method computed successfully. Returning data to Afterpay portal via resolve. shippingMethods=', response); // Need to handle case where address is unsupported/invalid if (!response.shipmethods || response.shipmethods.length == 0) { actions.reject(AfterPay.CONSTANTS.SHIPPING_ADDRESS_UNSUPPORTED); @@ -96,19 +88,15 @@ function initAfterpay(settings) { } }, error: function () { - console.log('Afterpay Express Checkout: failure in get shipping methods'); + alert('Afterpay payment failed.'); } }); }, onComplete: function (event) { if (event.data.status == 'SUCCESS') { - console.log('onComplete called with SUCCESS'); - console.log(event.data); var afterpayExpressProcessUrl = $('#afterpay-express-url-processorder').val() + '?orderToken=' + event.data.orderToken + '&merchantReference=' + event.data.merchantReference; $(location).attr('href', afterpayExpressProcessUrl); } else { - console.log('onComplete failed'); - console.log(event.data); var errorUrl = $('#afterpay-express-url-cancelorder').val() + '?orderToken=' + event.data.orderToken + '&merchantReference=' + event.data.merchantReference; $(location).attr('href', errorUrl); } @@ -131,11 +119,10 @@ function reinitializeAfterpayPopup() { url: getCartStatusUrl, success: function (res) { var instorepickup = res.instorepickup; - console.log('Instorepickup setting: ', instorepickup); initAfterpay(instorepickup); }, error: function () { - console.log('Afterpay Express cart status request failure.'); + alert('Afterpay payment failed.'); } }); } diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/afterpayWidget.js b/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/afterpayWidget.js index 3aa79c1..cb20f15 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/afterpayWidget.js +++ b/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/afterpayWidget.js @@ -6,18 +6,15 @@ function createAfterpayWidget () { target: '#afterpay-widget-container', locale: $('#afterpay-widget-locale').val().replace("_", "-"), onReady: function (event) { - console.log("onReady() called. event=", event); afterpayWidget.update({ - amount: { amount: $('#afterpay-widget-amount').val(), currency: $('#afterpay-widget-currency').val() }, + amount: { amount: $('#afterpay-widget-amount').val(), currency: $('#afterpay-widget-currency').val() } }); $('.afterpay-widget-hideuntilready').css("visibility", "visible"); // Fires when the widget is ready to accept updates. }, onChange: function (event) { - console.log("onChange() called. event=", event.data); if (!event.data.isValid) { let widgetErrorUrl = $('#afterpay-express-url-widgeterror').val() + "?error=" + encodeURIComponent(event.data.error); - console.log("Error with Afterpay Widget: " + event.data.error); window.location.assign(widgetErrorUrl); // Need to clear the session } @@ -25,7 +22,6 @@ function createAfterpayWidget () { // See "Getting the widget's state" for more details. }, onError: function (event) { - console.log("onError() called. event=", event); var errorUrl = $('#afterpay-express-url-cancelorder').val(); $(location).attr('href', errorUrl); // See "Handling widget errors" for more details. @@ -36,7 +32,7 @@ function createAfterpayWidget () { function priceUpdate() { afterpayWidget.update({ - amount: { amount: $('#afterpay-widget-amount').val(), currency: $('#afterpay-widget-currency').val() }, + amount: { amount: $('#afterpay-widget-amount').val(), currency: $('#afterpay-widget-currency').val() } }); } @@ -47,11 +43,8 @@ function checkCartAndUpdateWidget() { url: getCartStatusUrl, success: function(res) { afterpayWidget.update({ - amount: { amount: res.cartTotalAmount.toString(), currency: res.cartTotalCurrency }, + amount: { amount: res.cartTotalAmount.toString(), currency: res.cartTotalCurrency } }); - }, - error: function(){ - console.log("Afterpay Express cart status request failure."); } }); } diff --git a/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/cashAppWidget.js b/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/cashAppWidget.js new file mode 100644 index 0000000..442ef66 --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/static/default/js/cashAppWidget.js @@ -0,0 +1,45 @@ +function initCashAppPay(afterpaytoken) { + let commenceDelay = 0; + if(typeof AfterPay != "undefined"){ + var cashappProcessUrl; + $('.data-checkout-stage[data-checkout-stage=payment] button.submit-payment').css('display','none'); + var cashAppPayOptions = { + button: { + size: 'medium', // "medium" | "small" + width: 'full', // "full" | "static" + theme: 'dark', // "dark" | "light" + shape: 'semiround' // "round" | "semiround" + }, + redirectUrl: window.location.href, + onComplete: function(event) { + $.spinner().start(); + if(event.data){ + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?orderToken=' + event.data.orderToken + '&status=' + event.data.status; + window.location.href = cashappProcessUrl; + } + + }, + eventListeners: { + "CUSTOMER_REQUEST_DECLINED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=DECLINED'; + window.location.href = cashappProcessUrl; + }, + "CUSTOMER_REQUEST_FAILED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=FAILED'; + window.location.href = cashappProcessUrl; + } + } + } + } + sleep(commenceDelay).then(() => { + $('#cash-app-pay').css('display','block'); + $.spinner().stop(); + AfterPay.initializeForCashAppPay({countryCode: "US", token: afterpaytoken, cashAppPayOptions}); + }); + +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/cart/checkoutButtons.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/cart/checkoutButtons.isml index e5cb107..e67f31d 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/cart/checkoutButtons.isml +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/cart/checkoutButtons.isml @@ -14,7 +14,7 @@ afterpayExpressPickupEnabled - does the current cart and selected ship method in var BrandUtilities = require("*/cartridge/scripts/util/afterpayUtilities.js").brandUtilities; var countrycode = BrandUtilities.getCountryCode(); - var expressCheckoutJS = BrandUtilities.getBrandSettings().javaScriptUrl + "?merchant_key=demo"; + var expressCheckoutJS = BrandUtilities.getBrandSettings().javaScriptUrl; var sitePreferences = require("*/cartridge/scripts/util/afterpayUtilities.js").sitePreferencesUtilities; var afterpayEnabled = sitePreferences.isAfterpayEnabled(); var afterpayExpressCheckoutEnabled = afterpayEnabled ? sitePreferences.isExpressCheckoutEnabled() : false; diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppContent.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppContent.isml new file mode 100644 index 0000000..e7c74c9 --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppContent.isml @@ -0,0 +1,3 @@ +
+
diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppSummary.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppSummary.isml new file mode 100644 index 0000000..ad5dc19 --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppSummary.isml @@ -0,0 +1,4 @@ +
+ +
+
diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppTab.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppTab.isml new file mode 100644 index 0000000..afaf472 --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/cashAppTab.isml @@ -0,0 +1,10 @@ + diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsContent.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsContent.isml index adc5c05..b439d8d 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsContent.isml +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsContent.isml @@ -5,5 +5,7 @@ + + \ No newline at end of file diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsTabs.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsTabs.isml index 0518d39..6ecbd5c 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsTabs.isml +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/billing/paymentOptions/paymentOptionsTabs.isml @@ -5,5 +5,7 @@ + + - \ No newline at end of file + diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/cashAppMobile.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/cashAppMobile.isml new file mode 100644 index 0000000..606df1e --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/cashAppMobile.isml @@ -0,0 +1,11 @@ + + + + + + +
+
+

${Resource.msg('cashapppay.redirect.notification', 'afterpay', null)}

+

${Resource.msg('redirect.message', 'afterpay', null)}

+
diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/checkout.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/checkout.isml index d31f222..fb9deb4 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/checkout.isml +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/checkout/checkout.isml @@ -7,6 +7,7 @@ var assets = require('*/cartridge/scripts/assets.js'); assets.addJs('/js/checkout.js'); assets.addJs('/js/afterpayCheckout.js'); + assets.addJs('/js/cashappCheckout.js'); assets.addCss('/css/checkout/checkout.css'); assets.addCss('/css/afterpaystyle.css');
@@ -104,7 +105,11 @@
- + +
+ +
+
@@ -125,6 +130,9 @@ + Start of CashAppPay +
+ End of CashAppPay Start of Afterpay ${Resource.msg('clearpay.orderconfirmation.payment.method.name', 'clearpay', null)} + + ${Resource.msg('cashapppay.orderconfirmation.payment.method.name', 'clearpay', null)} + diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/common/scripts.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/common/scripts.isml index 6e30f7b..70eff79 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/common/scripts.isml +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/common/scripts.isml @@ -1,5 +1,6 @@ + - \ No newline at end of file + diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/product/components/cashappwidget.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/product/components/cashappwidget.isml new file mode 100644 index 0000000..a842059 --- /dev/null +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/product/components/cashappwidget.isml @@ -0,0 +1,15 @@ + + + var expressCheckoutJS = BrandUtilities.getBrandSettings().javaScriptUrl; + var sitePreferences = require("*/cartridge/scripts/util/afterpayUtilities.js").sitePreferencesUtilities; + var cashAppEnabled = sitePreferences.isCashAppEnabled(); + + + + + + + + + + diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/util/afterpayMessage.isml b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/util/afterpayMessage.isml index 46057bb..dd8223e 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/default/util/afterpayMessage.isml +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/default/util/afterpayMessage.isml @@ -28,7 +28,7 @@ rel="noreferrer noopener" href="${require('*/cartridge/scripts/util/afterpayUtilities').brandUtilities.getBrandSettings()['learnMoreUrl']}" > - ${Resource.msg('checkout.content.terms', pdict.brand, null)} + ${Resource.msg('terms.conditions.label', pdict.brand, null)} diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/afterpay.properties b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/afterpay.properties index c5839e2..f8499c7 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/afterpay.properties +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/afterpay.properties @@ -4,65 +4,49 @@ #log log.filename=afterpay -apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, were happy to help! -apierror.flow.400=Bad Request - Your request is a little wrong -apierror.flow.401=Unauthorized - Your API key is wrong -apierror.flow.402=Afterpay payment declined. Please select an alternative payment method. -apierror.flow.404=Not Found - The specified resource could not be found -apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method -apierror.flow.406=Not Acceptable - You requested a format that isn't json -apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation -apierror.flow.410=Gone - The resource requested has been removed from our servers -apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed +apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, we're happy to help! +apierror.flow.400=Bad Request - Your request is a little wrong. +apierror.flow.401=Unauthorized - Your API key is wrong. +apierror.flow.402=Payment declined. Please select an alternative payment method. +apierror.flow.404=Not Found - The specified resource could not be found. +apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method. +apierror.flow.406=Not Acceptable - You requested a format that isn't json. +apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation. +apierror.flow.410=Gone - The resource requested has been removed from our servers. +apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed. apierror.flow.422=Unprocessable Entity - The request format was valid, however one or more values were incorrect. apierror.flow.429=Too Many Requests - Too many requests may occur if an abnormal number of requests occur. apierror.flow.500=Internal Server Error - We had a problem with our server. Try again later. apierror.flow.503=Service Unavailable - We're temporarily offline for maintenance. Please try again later. apierror.flow.524=A timeout occurred -apierror.token.conflict=Invalid Payment Token‚ something went wrong‚ please try again! -afterpay.invalid.email.error=The Email Address entered contains invalid characters, please review and try again. -order.submission.error=Order cannot be placed because of some error. Please try after sometime. -afterpay.email.invalid.response=consumer.email not a well-formed email address +apierror.flow.invalid=There is an issue placing your Order. Your cart might have been changed. -afterpay.api.pending=Your payment is pending. -afterpay.api.error=An error occurred using Afterpay -afterpay.api.cancelled=Your payment has been cancelled -afterpay.api.declined=Your payment has been declined +afterpay.api.cancelled=Your payment has been cancelled. +afterpay.api.declined=Your payment has been declined. terms.conditions.label=Afterpay Terms & Conditions -payments.label=or make 4 interest-free payments of -learn.more.label=More info -with.label=fortnightly with -copyrights.label= © 2017 Afterpay -terms.link.label=Click here for complete terms. -terms.link.label.us=You must be over 18, a resident of the U.S and meet additional eligibility criteria to qualify. Late fees apply. -terms.link.us=Click here for complete terms. minimum.threshold.message=Afterpay is available for orders over {0} -maximum.threshold.message=The item is unavailable with -payment.tab.label=Installments by -checkout.content.terms=Terms and conditions -checkout.content.redirect.label=You will be redirected to Afterpay when you confirm your order +checkout.content.redirect.label=You will be redirected to Afterpay when you confirm your order. checkout.content.intro.text=Pay in -checkout.first.installment=First payment -checkout.second.installment=Two weeks later -checkout.third.installment=Four weeks later -checkout.fourth.installment=Six weeks later redirect.notification=Redirecting to Afterpay Payment Page. redirect.message=Please wait... -billing.logo=Afterpay -order.guest.email=NA dummy.email.id=test@afterpay.com footer.paymetns=Payments afterpay.orderconfirmation.payment.method.name=Afterpay -expresscheckout.error.multidestination=Afterpay Express Checkout unavailable for your cart (multiple destinations). Please proceed through normal checkout. expresscheckout.error.gettoken=Unable to get token. expresscheckout.error.emptycart=Cart is empty. expresscheckout.error.invalidsession=Invalid session. Please try again. expresscheckout.error.checkout=There was a problem with the Order. Please try again. expresscheckout.error.amountMismatch=Amount returned by Afterpay did not match expected amount. -expresscheckout.error.disabled=Afterpay Express Checkout not enabled. expresscheckout.error.notfinalizeflow=Not in express checkout finalize flow. Please check out again. expresscheckout.error.paymentinvalidsession=Invalid session. Unable to confirm order. -expresscheckout.error.invalidamount=Amount in cart does not qualify for Afterpay checkout +expresscheckout.error.invalidamount=Amount in cart does not qualify for Afterpay checkout. expresscheckout.error.missingchecksum=No widget checksum + +cashapppay.orderconfirmation.payment.method.name=Cash App +cashapppay.error.emailmissing=Please Enter Your Email-ID. +cashapppay.error.missmatch=The items in the cart does not match the Cash App Pay order items. +cashapppay.error.invalidamount=Amount in cart does not qualify for Cash App Pay checkout. +cashapppay.error.token=Cash App is having a problem with the order. Please select an alternative payment method. +cashapppay.redirect.notification=Processing your payment. diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay.properties b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay.properties index c5e2471..c7f8724 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay.properties +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay.properties @@ -2,66 +2,43 @@ # PLP/PDP message ############################################## #log -log.filename=afterpay +log.filename=clearpay -apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, were happy to help! -apierror.flow.400=Bad Request - Your request is a little wrong -apierror.flow.401=Unauthorized - Your API key is wrong +apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, we're happy to help! +apierror.flow.400=Bad Request - Your request is a little wrong. +apierror.flow.401=Unauthorized - Your API key is wrong. apierror.flow.402=Clearpay payment declined. Please select an alternative payment method. -apierror.flow.404=Not Found - The specified resource could not be found -apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method -apierror.flow.406=Not Acceptable - You requested a format that isn't json -apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation -apierror.flow.410=Gone - The resource requested has been removed from our servers -apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed +apierror.flow.404=Not Found - The specified resource could not be found. +apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method. +apierror.flow.406=Not Acceptable - You requested a format that isn't json. +apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation. +apierror.flow.410=Gone - The resource requested has been removed from our servers. +apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed. apierror.flow.422=Unprocessable Entity - The request format was valid, however one or more values were incorrect. apierror.flow.429=Too Many Requests - Too many requests may occur if an abnormal number of requests occur. apierror.flow.500=Internal Server Error - We had a problem with our server. Try again later. apierror.flow.503=Service Unavailable - We're temporarily offline for maintenance. Please try again later. apierror.flow.524=A timeout occurred -apierror.token.conflict=Invalid Payment Token‚ something went wrong‚ please try again! -afterpay.invalid.email.error=The Email Address entered contains invalid characters, please review and try again. -order.submission.error=Order cannot be placed because of some error. Please try after sometime. -afterpay.email.invalid.response=consumer.email not a well-formed email address +apierror.flow.invalid=There is an issue placing your Order. Your cart might have been changed. -afterpay.api.pending=Your payment is pending. -afterpay.api.error=An error occurred using Clearpay -afterpay.api.cancelled=Your payment has been cancelled -afterpay.api.declined=Your payment has been declined +afterpay.api.cancelled=Your payment has been cancelled. +afterpay.api.declined=Your payment has been declined. terms.conditions.label=Clearpay Terms & Conditions -payments.label=or make 4 interest-free payments of -learn.more.label=More info -with.label= fortnightly with -copyrights.label= © 2017 Clearpay -terms.link.label=Click here for complete terms. -terms.link.label.us=You must be over 18, a resident of the U.S and meet additional eligibility criteria to qualify. Late fees apply. -terms.link.us=Click here for complete terms. minimum.threshold.message=Clearpay is available for orders over {0} -maximum.threshold.message=The item is unavailable with -payment.tab.label=Installments by -checkout.content.terms=Terms and conditions -checkout.content.redirect.label=You will be redirected to Clearpay when you confirm your order +checkout.content.redirect.label=You will be redirected to Clearpay when you confirm your order. checkout.content.intro.text=Pay in -checkout.first.installment=First payment -checkout.second.installment=Two weeks later -checkout.third.installment=Four weeks later -checkout.fourth.installment=Six weeks later redirect.notification=Redirecting to Clearpay Payment Page. redirect.message=Please wait... -billing.logo=Clearpay -order.guest.email=NA dummy.email.id=test@clearpay.com clearpay.orderconfirmation.payment.method.name=Clearpay -expresscheckout.error.multidestination=Clearpay Express Checkout unavailable for your cart (multiple destinations). Please proceed through normal checkout. expresscheckout.error.gettoken=Unable to get token. expresscheckout.error.emptycart=Cart is empty. expresscheckout.error.invalidsession=Invalid session. Please try again. expresscheckout.error.checkout=There was a problem with the Order. Please try again. -expresscheckout.error.amountMismatch=Amount returned by Afterpay did not match expected amount. -expresscheckout.error.disabled=Clearpay Express Checkout not enabled. +expresscheckout.error.amountMismatch=Amount returned by Clearpay did not match expected amount. expresscheckout.error.notfinalizeflow=Not in express checkout finalize flow. Please check out again. expresscheckout.error.paymentinvalidsession=Invalid session. Unable to confirm order. -expresscheckout.error.invalidamount=Amount in cart does not qualify for Clearpay checkout +expresscheckout.error.invalidamount=Amount in cart does not qualify for Clearpay checkout. expresscheckout.error.missingchecksum=No widget checksum diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_es_ES.properties b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_es_ES.properties index 9f34ecd..7ec929c 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_es_ES.properties +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_es_ES.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Términos y condiciones -checkout.content.redirect.label=Serás redirigido a la plataforma de Clearpay para completar tu información de pago. -checkout.content.intro.text=Paga en \ No newline at end of file +apierror.flow.default=¡Uy! Parece que ha habido un problema. Si el error persiste, por favor háznoslo saber, ¡estaremos encantados de ayudarte! +apierror.flow.402=El pago con Clearpay ha sido rechazado. Por favor selecciona un método de pago alternativo +redirect.notification=Redirigiendo a la página de pago de Clearpay +redirect.message=Por favor, espera +terms.conditions.label=Términos y condiciones de Clearpay +checkout.content.redirect.label=Serás redirigido a Clearpay cuando confirmes el pedido +checkout.content.intro.text=Paga en +minimum.threshold.message=Clearpay está disponible para pedidos superiores a {0} +afterpay.api.declined=Tu pago ha sido rechazado +afterpay.api.cancelled=Tu pago ha sido cancelado diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_fr_FR.properties b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_fr_FR.properties index 1ac8f22..1b9483f 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_fr_FR.properties +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_fr_FR.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Conditions générales +apierror.flow.default=Oops! On dirait qu’on a eu un probleme. Si le probleme persiste, veuillez nous en informer, nous serons ravis de vous aider +apierror.flow.402=Paiement Clearpay refusé. Merci de sélectionner un mode de paiement alternatif +redirect.notification=Redirection vers la page de paiement de Clearpay +redirect.message=S.V.P attendre... +terms.conditions.label=Termes et conditions Clearpay checkout.content.redirect.label=Vous allez être redirigé vers Clearpay pour renseigner vos informations de paiement. -checkout.content.intro.text=Payez en \ No newline at end of file +checkout.content.intro.text=Payez en +minimum.threshold.message=Clearpay est disponible pour les commandes supérieures a {0} +afterpay.api.declined=Votre paiement a été refusé +afterpay.api.cancelled=Votre paiement a été annulé diff --git a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_it_IT.properties b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_it_IT.properties index 2da0c31..e429393 100644 --- a/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_it_IT.properties +++ b/cartridges/int_afterpay_sfra_6/cartridge/templates/resources/clearpay_it_IT.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Termini&Condizioni +apierror.flow.default=Ops! Sembra che abbiamo avuto un problema. Se il problema persiste, faccelo sapere, saremo felici di aiutarti +apierror.flow.402=Il pagamento Clearpay rifiuta. Seleziona un metodo di pagamento alternativo +redirect.message=Attendere prego... +redirect.notification=Reindirizzamento alla pagina di pagamento Clearpay +terms.conditions.label=Termini e condizioni Clearpay checkout.content.redirect.label=Verrai reindirizzato alla piattaforma Clearpay per completare il modulo con le informazioni relative al pagamento. -checkout.content.intro.text=Paga in \ No newline at end of file +checkout.content.intro.text=Paga in +minimum.threshold.message=Clearpay e disponibile per ordini superiori {0} +afterpay.api.declined=Il tuo pagamento è stato rifiutato +afterpay.api.cancelled=Il tuo pagamento è stato annullato diff --git a/cartridges/int_afterpay_sg/cartridge/controllers/AfterpayExpress.js b/cartridges/int_afterpay_sg/cartridge/controllers/AfterpayExpress.js index 78117c3..cfc45e8 100644 --- a/cartridges/int_afterpay_sg/cartridge/controllers/AfterpayExpress.js +++ b/cartridges/int_afterpay_sg/cartridge/controllers/AfterpayExpress.js @@ -486,7 +486,7 @@ function IntegratedShippingFlow(afterPayOrderResponse) { (adjustCartResponse.totalCost.currencyCode != currency)) { // this can occur if session was modified while express checkout was in flight Logger.error('Amount returned by Afterpay did not match expected amount. Afterpay returned=' + amount + currency + ' Merchant computed=' + adjustCartResponse.totalCost.value + adjustCartResponse.totalCost.currencyCode); - redirectToErrorDisplay(Resource.msg('apierror.token.conflict', brand, null)); + redirectToErrorDisplay(Resource.msg('expresscheckout.error.amountMismatch', brand, null)); return; } diff --git a/cartridges/int_afterpay_sg/cartridge/controllers/AfterpayRedirect.js b/cartridges/int_afterpay_sg/cartridge/controllers/AfterpayRedirect.js index a70fa6e..bd7b88d 100644 --- a/cartridges/int_afterpay_sg/cartridge/controllers/AfterpayRedirect.js +++ b/cartridges/int_afterpay_sg/cartridge/controllers/AfterpayRedirect.js @@ -59,14 +59,8 @@ function HandleResponse() { orderToken: orderTokenString }); - if (!productExists) { - if (productExists.error) { - redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('apierror.flow.default', session.privacy.afterpayBrand, null)); - } - - redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('apierror.token.conflict', session.privacy.afterpayBrand, null)); - } else if (PreapprovalResult.error) { - redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('apierror.flow.default', session.privacy.afterpayBrand, null)); + if (!productExists || PreapprovalResult.error) { + redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('apierror.flow.invalid', session.privacy.afterpayBrand, null)); } else { try { placeOrderResult = COPlaceOrder.Start(); // eslint-disable-line diff --git a/cartridges/int_afterpay_sg/cartridge/controllers/CashApp.js b/cartridges/int_afterpay_sg/cartridge/controllers/CashApp.js new file mode 100644 index 0000000..8704d2a --- /dev/null +++ b/cartridges/int_afterpay_sg/cartridge/controllers/CashApp.js @@ -0,0 +1,113 @@ +'use strict'; + +/* global empty, request */ +/* API Includes */ +var URLUtils = require('dw/web/URLUtils'); +var Resource = require('dw/web/Resource'); + +/* Global variables */ +var AfterpayUtilities = require('*/cartridge/scripts/util/afterpayUtilities'); +var sitePreferences = AfterpayUtilities.sitePreferencesUtilities; +var apBrandUtilities = AfterpayUtilities.brandUtilities; +var AfterpaySession = require('*/cartridge/scripts/util/afterpaySession'); +var AfterpayCOHelpers = require('*/cartridge/scripts/checkout/afterpayCheckoutHelpers'); + +/* Script Modules */ +var ctrlCartridgeName = sitePreferences.getControllerCartridgeName(); +var app = require(ctrlCartridgeName + '/cartridge/scripts/app'); +var guard = require(ctrlCartridgeName + '/cartridge/scripts/guard'); +var COPlaceOrder = require('*/cartridge/controllers/COPlaceOrder'); +var COSummary = require('*/cartridge/controllers/COSummary'); +var Cart = app.getModel('Cart'); +var LogUtils = require('*/cartridge/scripts/util/afterpayLogUtils'); +var Logger = LogUtils.getLogger('CashApp'); + +/** + * Handles the payment status returned by the Afterpay. Based on the status Order will be submitted . + */ +function HandleResponse() { + var cart; + var paymentStatus; + var redirectURL; + var PreapprovalResult; + var placeOrderResult; + var basketValid = false; + + cart = Cart.get(); + + paymentStatus = request.httpParameterMap.status.getStringValue(); + var itemsChecksum = AfterpayCOHelpers.computeBasketProductLineItemChecksum(cart.object); + if(AfterpaySession.isValid()) { + if (itemsChecksum == AfterpaySession.getItemsChecksum()) { + basketValid = true; + } + AfterpaySession.clearSession(); + } + + if(basketValid) { + if (paymentStatus === 'SUCCESS') { + var orderTokenString = request.httpParameterMap.orderToken.getStringValue(); + PreapprovalResult = require('*/cartridge/scripts/checkout/afterpayUpdatePreapprovalStatus').getPreApprovalResult(cart.object, { + status: paymentStatus, + orderToken: orderTokenString, + isCashAppPay: 'true' + }); + + if (PreapprovalResult.error) { + redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('apierror.flow.default', session.privacy.afterpayBrand, null)); + } else { + try { + placeOrderResult = COPlaceOrder.Start(); // eslint-disable-line + Logger.debug('PlaceOrder status :' + JSON.stringify(placeOrderResult)); + + if (placeOrderResult.order_created) { + COSummary.ShowConfirmation(placeOrderResult.Order); // eslint-disable-line + } else if (placeOrderResult.error) { + var error = !empty(placeOrderResult.afterpayOrderAuthorizeError) ? placeOrderResult.afterpayOrderAuthorizeError : Resource.msg('apierror.flow.default', session.privacy.afterpayBrand, null); + redirectURL = URLUtils.https('COBilling-Start', 'afterpay', error); + } + } catch (e) { + Logger.error('Exception occured while creating order :' + e); + redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('apierror.flow.default', session.privacy.afterpayBrand, null)); + } + } + } else if (paymentStatus === 'CANCELLED') { + redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('afterpay.api.cancelled', session.privacy.afterpayBrand, null)); + } else if (paymentStatus === 'DECLINED') { + redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('afterpay.api.declined', session.privacy.afterpayBrand, null)); + } else { + redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('apierror.flow.default', session.privacy.afterpayBrand, null)); + } + } else { + redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('cashapppay.error.missmatch', session.privacy.afterpayBrand, null)); + } + + if (!empty(redirectURL)) { + app.getView({ + AfterpayRedirectUrl: redirectURL + }).render('checkout/redirect'); + } +} + +function HandleMobileResponse() { + var cash_request_id = request.httpParameterMap.cash_request_id.getStringValue(); + if (!empty(cash_request_id)) { + var scriptURL = apBrandUtilities.getBrandSettings().javaScriptUrl; + app.getView({ + apJavascriptURL: scriptURL + }).render('checkout/cashAppMobile'); + } else { + var redirectURL = URLUtils.https('COBilling-Start', 'afterpay', Resource.msg('cashapppay.error.missmatch', session.privacy.afterpayBrand, null)); + app.getView({ + AfterpayRedirectUrl: redirectURL + }).render('checkout/redirect'); + } +} + +/* +* Web exposed methods +*/ +/** Payment status handling. + * @see module:controllers/AfterpayRedirect~Confirm */ +exports.HandleResponse = guard.ensure(['https'], HandleResponse); +exports.HandleMobileResponse = guard.ensure(['https'], HandleMobileResponse); diff --git a/cartridges/int_afterpay_sg/cartridge/scripts/checkout/afterpayHandlers.js b/cartridges/int_afterpay_sg/cartridge/scripts/checkout/afterpayHandlers.js index c82670b..ddf6dcc 100644 --- a/cartridges/int_afterpay_sg/cartridge/scripts/checkout/afterpayHandlers.js +++ b/cartridges/int_afterpay_sg/cartridge/scripts/checkout/afterpayHandlers.js @@ -9,8 +9,8 @@ var apHandlers = { // recompute the amount for the Afterpay payment instrument recomputeAfterpayPayment: function() { var AfterpaySession = require('*/cartridge/scripts/util/afterpaySession'); - var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); if (AfterpaySession.isExpressCheckout()) { + var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); var Transaction = require('dw/system/Transaction'); var cart = app.getModel('Cart').get(); @@ -30,13 +30,14 @@ var apHandlers = { } }, // only call when changing to non-Afterpay payment method - handleChangedPaymentInstrument: function() { - var AfterpaySession = require('*/cartridge/scripts/util/afterpaySession'); - var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(); - var cart = app.getModel('Cart').get(); - cart.removePaymentInstruments( cart.getPaymentInstruments(paymentMethodName)); - // clears all session vars used by Afterpay - AfterpaySession.clearSession(); + handleChangedPaymentInstrument: function(paymentMethod) { + if (paymentMethod != 'CASHAPPPAY') { + this.removePaymentMethods(true); + } + if (paymentMethod != 'AFTERPAY' && paymentMethod != 'CLEARPAY') { + this.removePaymentMethods(); + } + }, // When the shipping method is updated, we need to update the Afterpay // payment in the cart with the correct amount @@ -45,8 +46,15 @@ var apHandlers = { }, handleBillingStart: function() { this.recomputeAfterpayPayment(); + }, + removePaymentMethods: function(isCashAppPay){ + var AfterpaySession = require('*/cartridge/scripts/util/afterpaySession'); + var paymentMethodName = apCheckoutUtilities.getPaymentMethodName(isCashAppPay); + var cart = app.getModel('Cart').get(); + cart.removePaymentInstruments( cart.getPaymentInstruments(paymentMethodName)); + // clears all session vars used by Afterpay + AfterpaySession.clearSession(); } - }; module.exports = apHandlers; diff --git a/cartridges/int_afterpay_sg/cartridge/scripts/hooks.json b/cartridges/int_afterpay_sg/cartridge/scripts/hooks.json index eda5338..5f175ef 100644 --- a/cartridges/int_afterpay_sg/cartridge/scripts/hooks.json +++ b/cartridges/int_afterpay_sg/cartridge/scripts/hooks.json @@ -4,9 +4,13 @@ "name": "app.payment.processor.AFTERPAY_CREDIT", "script": "./payment/processor/AFTERPAY_CREDIT" }, + { + "name": "app.payment.processor.CASHAPP_CREDIT", + "script": "./payment/processor/CASHAPP_CREDIT" + }, { "name": "dw.system.request.onSession", "script": "./request/OnSession" } ] -} \ No newline at end of file +} diff --git a/cartridges/int_afterpay_sg/cartridge/scripts/payment/processor/CASHAPPPAY.js b/cartridges/int_afterpay_sg/cartridge/scripts/payment/processor/CASHAPPPAY.js new file mode 100644 index 0000000..7c98f87 --- /dev/null +++ b/cartridges/int_afterpay_sg/cartridge/scripts/payment/processor/CASHAPPPAY.js @@ -0,0 +1,155 @@ +'use strict'; +/* global empty, request */ + +/* API Includes */ +var Transaction = require('dw/system/Transaction'); +var AfterpayUtilities = require('*/cartridge/scripts/util/afterpayUtilities.js'); +var sitePreferences = AfterpayUtilities.sitePreferencesUtilities; +var ctrlCartridgeName = sitePreferences.getControllerCartridgeName(); +var Cart = require(ctrlCartridgeName + '/cartridge/scripts/models/CartModel'); +var OrderMgr = require('dw/order/OrderMgr'); +var Status = require('dw/system/Status'); +var Resource = require('dw/web/Resource'); + +/* Script Modules */ +var app = require(ctrlCartridgeName + '/cartridge/scripts/app'); +var brandUtilities = AfterpayUtilities.brandUtilities; +var LogUtils = require('*/cartridge/scripts/util/afterpayLogUtils'); +var Logger = LogUtils.getLogger('CASHAPP'); +var AfterpaySession = require('*/cartridge/scripts/util/afterpaySession'); +var AfterpayCOHelpers = require('*/cartridge/scripts/checkout/afterpayCheckoutHelpers'); + +/** + * Handles Afterpay token generation process + * @param {Object} args - arguments + * @returns {Object} response - response + */ +function Handle(args) { + var cart = Cart.get(args.Basket); + + Transaction.wrap(function () { + cart.removeExistingPaymentInstruments('CASHAPPPAY'); + cart.createPaymentInstrument('CASHAPPPAY', cart.getNonGiftCertificateAmount()); + }); + + // Recalculate the payments. If there is only gift certificates, make sure it covers the order total, if not + // back to billing page. + Transaction.wrap(function () { + if (!cart.calculatePaymentTransactionTotal()) { + app.getController('COBilling').Start(); // eslint-disable-line + } + + return {}; + }); + + var afterPayTokenResponse = require('*/cartridge/scripts/checkout/afterpayGetToken').getToken(args.Basket,true); + Logger.debug('Token value returned to - CASHAPPPAY.JS : ' + JSON.stringify(afterPayTokenResponse)); + + var afterPayToken = afterPayTokenResponse.errorMessage ? afterPayTokenResponse.errorMessage : afterPayTokenResponse; + var responseCode = AfterpayUtilities.checkoutUtilities.getPaymentResponseCode(afterPayTokenResponse); + + if (afterPayTokenResponse.error) { + var errorMessage = require('*/cartridge/scripts/util/afterpayErrors').getErrorResponses(responseCode, true); + Logger.error('Error while generating Token : ' + errorMessage); + return { + error: true + }; + } + + if(AfterpaySession.isValid()) { + AfterpaySession.clearSession(); + } + AfterpaySession.newSession(afterPayToken.apToken); + AfterpaySession.setItemsChecksum(AfterpayCOHelpers.computeBasketProductLineItemChecksum(cart.object)); + AfterpaySession.setIsCashAppPay(true); + return { + success: true + }; +} + +/** + * Authorizes Afterpay Order process. + * @param {Object} args - arguments + * @returns {Object} response - response + */ +function Authorise(args) { + var response; + var finalPaymentStatus; + var errorMessage; + var responseCode; + var Order = OrderMgr.getOrder(args.OrderNo); + var apInitialStatus = Order.getPaymentInstruments('CASHAPPPAY')[0].getPaymentTransaction().custom.apInitialStatus; + var orderToken = Order.getPaymentInstruments('CASHAPPPAY')[0].getPaymentTransaction().custom.apToken; + var expressCheckoutModel = null; + + Logger.debug('CashApp getToken :' + AfterpaySession.getToken()); + if (AfterpaySession.isValid()) { + if (AfterpaySession.getToken() != orderToken) { + Transaction.begin(); + Order.getPaymentInstruments('CASHAPPPAY')[0].getPaymentTransaction().custom.apInitialStatus = apInitialStatus; + Order.setPaymentStatus(dw.order.Order.PAYMENT_STATUS_NOTPAID); + OrderMgr.failOrder(Order); + Transaction.commit(); + Logger.error('Payment has been declined. Session changed so there is no way to verify that order created was correct.'); + AfterpaySession.clearSession(); + + return { + AfterpayOrderErrorMessage: Resource.msg('expresscheckout.error.paymentinvalidsession', brandUtilities.getBrand(), null), + error: true + }; + } + } + // Clear the Afterpay session regardless of capture outcome + AfterpaySession.clearSession(); + Logger.debug('Afterpay Initial payment status :' + apInitialStatus); + finalPaymentStatus = require('*/cartridge/scripts/checkout/afterpayHandlePaymentOrder').getPaymentStatus(Order, apInitialStatus, expressCheckoutModel,'true'); + response = !empty(finalPaymentStatus.errorMessage) ? finalPaymentStatus.errorMessage : finalPaymentStatus; + responseCode = AfterpayUtilities.checkoutUtilities.getPaymentResponseCode(finalPaymentStatus); + + if (response === 'SERVICE_UNAVAILABLE' || response.httpStatusCode === 500 || response === 'INTERNAL_SERVICE_ERROR') { + finalPaymentStatus = require('*/cartridge/scripts/checkout/afterpayIdempotency').delayPayment(Order, apInitialStatus, expressCheckoutModel); + } + + Logger.debug('Afterpay final payment status :' + finalPaymentStatus); + + if (finalPaymentStatus === 'APPROVED') { + return { authorized: true }; + } else if (finalPaymentStatus === 'PENDING') { + return { + error: true, + PlaceOrderError: new Status(Status.ERROR, apInitialStatus, 'afterpay.api.declined'), + apInitialStatus: !empty(Order.getPaymentInstruments('CASHAPPPAY')[0].getPaymentTransaction().custom.apInitialStatus) ? Order.getPaymentInstruments('CASHAPPPAY')[0].getPaymentTransaction().custom.apInitialStatus : null + }; + } else if (finalPaymentStatus === 'DECLINED') { + errorMessage = require('*/cartridge/scripts/util/afterpayErrors').getErrorResponses(responseCode, true); + Transaction.begin(); + Order.getPaymentInstruments('CASHAPPPAY')[0].getPaymentTransaction().custom.apInitialStatus = apInitialStatus; + Transaction.commit(); + + Logger.error('Payment has been declined : ' + responseCode); + return { + AfterpayOrderErrorMessage: errorMessage, + error: true + }; + } + + if (finalPaymentStatus.error) { + errorMessage = require('*/cartridge/scripts/util/afterpayErrors').getErrorResponses(responseCode, true); + Transaction.begin(); + Order.getPaymentInstruments('CASHAPPPAY')[0].getPaymentTransaction().custom.apInitialStatus = apInitialStatus; + Transaction.commit(); + + Logger.error('Error while Authorizing Order : ' + responseCode); + } + + return { + AfterpayOrderErrorMessage: errorMessage, + error: true + }; +} + +/* + * Local methods + */ +exports.Handle = Handle; +exports.Authorise = Authorise; diff --git a/cartridges/int_afterpay_sg/cartridge/scripts/payment/processor/CASHAPP_CREDIT.js b/cartridges/int_afterpay_sg/cartridge/scripts/payment/processor/CASHAPP_CREDIT.js new file mode 100644 index 0000000..eebce48 --- /dev/null +++ b/cartridges/int_afterpay_sg/cartridge/scripts/payment/processor/CASHAPP_CREDIT.js @@ -0,0 +1,77 @@ +'use strict'; + +/* Script Modules */ +var LogUtils = require('*/cartridge/scripts/util/afterpayLogUtils'); +var BrandMapping = require('*/cartridge/scripts/brandMapping'); +var Logger = LogUtils.getLogger('CashApp_Credit'); + +/** + * Calls Handle of CASHAPPPAY + * @param {Object} args - arguments + * @returns {Object} response - response + */ +function Handle(args) { + var mapping = BrandMapping['cashapp']; + var processorPath = null; + + if (mapping) { + processorPath = mapping.paymentProcessor; + + if (!processorPath) { + return { + error: true + }; + } + } + + var response = require(processorPath).Handle(args); // eslint-disable-line + + if (response.error) { + return { + error: true + }; + } + + return { + success: true + }; +} + +/** + * Calls Authorize of CASHAPPPAY + * @param {Object} args - arguments + * @returns {Object} response - response + */ +function Authorize(args) { + var mapping = BrandMapping['cashapp']; + var processorPath = null; + + if (mapping) { + processorPath = mapping.paymentProcessor; + + if (!processorPath) { + return { + error: true + }; + } + } + + var authorizationStatus = require(processorPath).Authorise(args); // eslint-disable-line + + Logger.debug('Authorization response in CASHAPP_CREDIT: ' + JSON.stringify(authorizationStatus)); + + if (authorizationStatus.authorized) { + return { authorized: true }; + } + + return { + authorizationResponse: authorizationStatus.AfterpayOrderErrorMessage, + error: true + }; +} + +/* + * Local methods + */ +exports.Handle = Handle; +exports.Authorize = Authorize; diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge.png b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge.png new file mode 100644 index 0000000..062aa7f Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge.png differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge1x.png b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge1x.png new file mode 100644 index 0000000..641dba5 Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge1x.png differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge2x.png b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge2x.png new file mode 100644 index 0000000..0c54392 Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge2x.png differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge3x.png b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge3x.png new file mode 100644 index 0000000..b3aa32a Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapp-badge3x.png differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg new file mode 100644 index 0000000..00eb73c Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark-preview-sm.jpg differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark.png b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark.png new file mode 100644 index 0000000..abd315d Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark.png differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark1x.png b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark1x.png new file mode 100644 index 0000000..6ccd20c Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark1x.png differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark2x.png b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark2x.png new file mode 100644 index 0000000..de23c57 Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark2x.png differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark3x.png b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark3x.png new file mode 100644 index 0000000..6ee258e Binary files /dev/null and b/cartridges/int_afterpay_sg/cartridge/static/default/images/cashapppay-logomark3x.png differ diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/js/afterpayExpress.js b/cartridges/int_afterpay_sg/cartridge/static/default/js/afterpayExpress.js index 6cdf97f..cb54118 100644 --- a/cartridges/int_afterpay_sg/cartridge/static/default/js/afterpayExpress.js +++ b/cartridges/int_afterpay_sg/cartridge/static/default/js/afterpayExpress.js @@ -34,12 +34,11 @@ function initAfterpay(settings) { } else { afterpayCreateTokenErrorMessage = res.error; alert(res.error); - console.log('Afterpay Express Checkout: Token Creation Failure: ', res.error); actions.reject(AfterPay.CONSTANTS.SERVICE_UNAVAILABLE); } }, error: function () { - console.log('Afterpay Express Checkout: request failure.'); + alert('Afterpay payment failed.'); } }); }); @@ -72,7 +71,7 @@ function initAfterpay(settings) { } }, error: function () { - console.log('Afterpay Express Checkout: failure in get shipping methods'); + alert('Afterpay payment failed.'); } }); }, @@ -106,7 +105,7 @@ function reinitializeAfterpayPopup() { initAfterpay({ pickupflag: instorepickup }); }, error: function () { - console.log('Afterpay Express cart status request failure.'); + alert('Afterpay payment failed.'); } }); } diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/js/afterpayWidget.js b/cartridges/int_afterpay_sg/cartridge/static/default/js/afterpayWidget.js index 80775d3..58d6eab 100644 --- a/cartridges/int_afterpay_sg/cartridge/static/default/js/afterpayWidget.js +++ b/cartridges/int_afterpay_sg/cartridge/static/default/js/afterpayWidget.js @@ -15,7 +15,6 @@ function createAfterpayWidget() { onChange: function (event) { if (!event.data.isValid) { let widgetErrorUrl = $('#afterpay-express-url-widgeterror').val() + "?error=" + encodeURIComponent(event.data.error); - console.log("Error with Afterpay Widget: " + event.data.error); window.location.assign(widgetErrorUrl); // Need to clear the session } @@ -25,7 +24,6 @@ function createAfterpayWidget() { // See "Getting the widget's state" for more details. }, onError: function (event) { - console.log("onError() called. event=", event); var errorUrl = $('#afterpay-express-url-cancelorder').val(); $(location).attr('href', errorUrl); // See "Handling widget errors" for more details. @@ -52,11 +50,8 @@ function checkCartAndUpdateWidget() { amount: { amount: res.cartTotalAmount.toString(), currency: res.cartTotalCurrency - }, + } }); - }, - error: function () { - console.log("Afterpay Express cart status request failure."); } }); } diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/js/cashAppWidget.js b/cartridges/int_afterpay_sg/cartridge/static/default/js/cashAppWidget.js new file mode 100644 index 0000000..a4508de --- /dev/null +++ b/cartridges/int_afterpay_sg/cartridge/static/default/js/cashAppWidget.js @@ -0,0 +1,46 @@ +function initCashAppPay(afterpaytoken) { + let commenceDelay = 0; + if(typeof AfterPay != "undefined"){ + $('.data-checkout-stage[data-checkout-stage=payment] button.submit-payment').css('display','none'); + var cashAppPayOptions = { + button: { + size: 'medium', // "medium" | "small" + width: 'full', // "full" | "static" + theme: 'dark', // "dark" | "light" + shape: 'semiround' // "round" | "semiround" + }, + onComplete: function(event) { + if(event.data){ + var cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?orderToken=' + event.data.orderToken + '&status=' + event.data.status; + window.location.href = cashappProcessUrl; + } + + }, + eventListeners: { + "CUSTOMER_REQUEST_DECLINED": () => { + var cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=DECLINED'; + window.location.href = cashappProcessUrl; + }, + "CUSTOMER_REQUEST_FAILED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=FAILED'; + window.location.href = cashappProcessUrl; + } + } + } + } + sleep(commenceDelay).then(() => { + $('#cash-app-pay').css('display','block') + AfterPay.initializeForCashAppPay({countryCode: "US", token: afterpaytoken, cashAppPayOptions}); + }); +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +$(document).ready(function () { + if($('#cashApp-token').val()!= 'undefined' && $('#cashApp-token').val().length != 0){ + var cashAppToken = $('#cashApp-token').val(); + initCashAppPay(cashAppToken); + } +}); diff --git a/cartridges/int_afterpay_sg/cartridge/static/default/js/cashappCheckoutMobile.js b/cartridges/int_afterpay_sg/cartridge/static/default/js/cashappCheckoutMobile.js new file mode 100644 index 0000000..603b14e --- /dev/null +++ b/cartridges/int_afterpay_sg/cartridge/static/default/js/cashappCheckoutMobile.js @@ -0,0 +1,34 @@ +'use strict'; +/* global $ */ +function onPageLoad(){ + var cashappProcessUrl; + var cashAppPayListenerOptions = { + onComplete: function(event) { + const { status, cashtag, orderToken} = event.data; + if(event.data){ + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?orderToken=' + event.data.orderToken + '&status=' + event.data.status; + window.location.href = cashappProcessUrl; + } + }, + /* Optional event listeners for merchants to track customer behavior and listen for transaction events in the lifecycle */ + eventListeners: { + "CUSTOMER_REQUEST_DECLINED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=DECLINED'; + window.location.href = cashappProcessUrl; + }, + "CUSTOMER_REQUEST_FAILED": () => { + cashappProcessUrl = $('#cashApp-url-handleresponse').val() + '?status=FAILED'; + window.location.href = cashappProcessUrl; + } + } + } + if(AfterPay != 'undefined'){ + $(".loader-image").fadeOut("slow"); + AfterPay.initializeCashAppPayListeners({countryCode: "US", cashAppPayListenerOptions}); + } +} + +window.onload = function () { + $(".loader-image").fadeOut("slow"); + onPageLoad(); +}; diff --git a/cartridges/int_afterpay_sg/cartridge/templates/default/checkout/cashAppMobile.isml b/cartridges/int_afterpay_sg/cartridge/templates/default/checkout/cashAppMobile.isml new file mode 100644 index 0000000..606df1e --- /dev/null +++ b/cartridges/int_afterpay_sg/cartridge/templates/default/checkout/cashAppMobile.isml @@ -0,0 +1,11 @@ + + + + + + +
+
+

${Resource.msg('cashapppay.redirect.notification', 'afterpay', null)}

+

${Resource.msg('redirect.message', 'afterpay', null)}

+
diff --git a/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/afterpaymessage.isml b/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/afterpaymessage.isml index 75989df..0bb01a6 100644 --- a/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/afterpaymessage.isml +++ b/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/afterpaymessage.isml @@ -42,7 +42,7 @@ diff --git a/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/afterpaywidget.isml b/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/afterpaywidget.isml index 98313fe..115cbcd 100644 --- a/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/afterpaywidget.isml +++ b/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/afterpaywidget.isml @@ -12,18 +12,25 @@ + var afterpayToken; + var isCashApp = false; var sitePreferences = require("*/cartridge/scripts/util/afterpayUtilities").sitePreferencesUtilities; var afterpayEnable = sitePreferences.isAfterpayEnabled(); + var cashAppEnabled = sitePreferences.isCashAppEnabled(); + var isExpressCheckoutFinalize; + var afterpayExpressCheckoutEnabled = afterpayEnable && sitePreferences.isExpressCheckoutEnabled(); // session state specifically used for Afterpay Express var AfterpaySession = require('*/cartridge/scripts/util/afterpaySession'); - var afterpayToken = AfterpaySession.getToken(); - var isExpressCheckoutFinalize = AfterpaySession.isExpressCheckoutFinalizeFlow(); - var afterpayExpressCheckoutEnabled = sitePreferences.isExpressCheckoutEnabled(); + if (AfterpaySession.isValid()) { + afterpayToken = AfterpaySession.getToken(); + isCashApp = AfterpaySession.getIsCashAppPay() && cashAppEnabled; + isExpressCheckoutFinalize = AfterpaySession.isExpressCheckoutFinalizeFlow(); + } + var BrandUtilities = require("*/cartridge/scripts/util/afterpayUtilities.js").brandUtilities; - var countrycode = BrandUtilities.getCountryCode(); - var expressCheckoutJS = BrandUtilities.getBrandSettings().javaScriptUrl + "?merchant_key=demo"; + var expressCheckoutJS = BrandUtilities.getBrandSettings().javaScriptUrl; var afterpayAmount = require('*/cartridge/scripts/checkout/afterpayCheckoutHelpers').getCurrentAfterpayPaymentAmount(dw.order.BasketMgr.getCurrentBasket()); - if (afterpayAmount.value == 0) { + if (afterpayAmount.value == 0 && !isCashApp) { // If we've reached the billing page and there's no existing Afterpay payment transaction in the basket, clear the // session since we're obviously not the normal express checkout flow AfterpaySession.clearSession(); // clear session. widget will not be displayed since checked flags will return false. @@ -43,4 +50,4 @@ - \ No newline at end of file + diff --git a/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/cashappwidget.isml b/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/cashappwidget.isml new file mode 100644 index 0000000..6906699 --- /dev/null +++ b/cartridges/int_afterpay_sg/cartridge/templates/default/product/components/cashappwidget.isml @@ -0,0 +1,14 @@ + + + + + +
+ + + + + +
+
+
diff --git a/cartridges/int_afterpay_sg/cartridge/templates/default/util/modulesafterpay.isml b/cartridges/int_afterpay_sg/cartridge/templates/default/util/modulesafterpay.isml index 1613034..d815bdd 100644 --- a/cartridges/int_afterpay_sg/cartridge/templates/default/util/modulesafterpay.isml +++ b/cartridges/int_afterpay_sg/cartridge/templates/default/util/modulesafterpay.isml @@ -20,3 +20,7 @@ name="afterpayexpresscheckout" attribute="pagetype" /> + + diff --git a/cartridges/int_afterpay_sg/cartridge/templates/resources/afterpay.properties b/cartridges/int_afterpay_sg/cartridge/templates/resources/afterpay.properties index 48e6720..b4df7d1 100644 --- a/cartridges/int_afterpay_sg/cartridge/templates/resources/afterpay.properties +++ b/cartridges/int_afterpay_sg/cartridge/templates/resources/afterpay.properties @@ -4,44 +4,32 @@ #log log.filename=afterpay - -apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, were happy to help! -apierror.flow.400=Bad Request - Your request is a little wrong -apierror.flow.401=Unauthorized - Your API key is wrong +apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, we're happy to help! +apierror.flow.400=Bad Request - Your request is a little wrong. +apierror.flow.401=Unauthorized - Your API key is wrong. apierror.flow.402=Afterpay payment declined. Please select an alternative payment method. -apierror.flow.404=Not Found - The specified resource could not be found -apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method -apierror.flow.406=Not Acceptable - You requested a format that isn't json -apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation -apierror.flow.410=Gone - The resource requested has been removed from our servers -apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed +apierror.flow.404=Not Found - The specified resource could not be found. +apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method. +apierror.flow.406=Not Acceptable - You requested a format that isn't json. +apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation. +apierror.flow.410=Gone - The resource requested has been removed from our servers. +apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed. apierror.flow.422=Unprocessable Entity - The request format was valid, however one or more values were incorrect. apierror.flow.429=Too Many Requests - Too many requests may occur if an abnormal number of requests occur. apierror.flow.500=Internal Server Error - We had a problem with our server. Try again later. apierror.flow.503=Service Unavailable - We're temporarily offline for maintenance. Please try again later. apierror.flow.524=A timeout occurred -apierror.token.conflict=Invalid Payment Token‚ something went wrong‚ please try again! - -afterpay.api.pending=Your payment is pending. -afterpay.api.error=An error occurred using Afterpay -afterpay.api.cancelled=Your payment has been cancelled -afterpay.api.declined=Your payment has been declined +apierror.flow.invalid=There is an issue placing your Order. Your cart might have been changed. +afterpay.api.cancelled=Your payment has been cancelled. +afterpay.api.declined=Your payment has been declined. terms.conditions.label=Afterpay Terms & Conditions -payments.label=or make 4 interest-free payments of -learn.more.label=More info -with.label= fortnightly with -terms.link.label=Click here for complete terms. -terms.link.label.us=You must be over 18, a resident of the U.S and meet additional eligibility criteria to qualify. Late fees apply. -terms.link.us=Click here for complete terms. minimum.threshold.message=Afterpay is available for orders over {0} -maximum.threshold.message=The item is unavailable with redirect.notification=Redirecting to Afterpay Payment Page. redirect.message=Please wait... -billing.logo=Afterpay +dummy.email.id=test@afterpay.com -checkout.content.terms=Terms and conditions -checkout.content.redirect.label=You will be redirected to Afterpay when you confirm your order +checkout.content.redirect.label=You will be redirected to Afterpay when you confirm your order. checkout.content.intro.text=Pay in expresscheckout.error.multidestination=Afterpay Express Checkout unavailable for your cart (multiple destinations). Please proceed through normal checkout. @@ -53,3 +41,10 @@ expresscheckout.error.amountMismatch=Amount returned by Afterpay did not match e expresscheckout.error.disabled=Afterpay Express Checkout not enabled. expresscheckout.error.notfinalizeflow=Not in express checkout finalize flow. expresscheckout.error.paymentinvalidsession=Invalid session. Unable to confirm order. + +cashapppay.error.emailmissing=Please Enter Your Email-ID. +cashapppay.error.missmatch=The items in the cart does not match the Cash App Pay order items. +cashapppay.error.invalidamount=Amount in cart does not qualify for Cash App Pay checkout. +cashapppay.error.token=Cash App is having a problem with the order. Please select an alternative payment method. +cashapppay.checkout.message=You will be redirected to Cash App pay. +cashapppay.redirect.notification=Processing your payment. diff --git a/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay.properties b/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay.properties index 1705594..42cb176 100644 --- a/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay.properties +++ b/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay.properties @@ -4,52 +4,40 @@ #log log.filename=clearpay - -apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, were happy to help! -apierror.flow.400=Bad Request - Your request is a little wrong -apierror.flow.401=Unauthorized - Your API key is wrong +apierror.flow.default=Oops! Looks like we had a problem. If the issue persists, please let us know, we're happy to help! +apierror.flow.400=Bad Request - Your request is a little wrong. +apierror.flow.401=Unauthorized - Your API key is wrong. apierror.flow.402=Clearpay payment declined. Please select an alternative payment method. -apierror.flow.404=Not Found - The specified resource could not be found -apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method -apierror.flow.406=Not Acceptable - You requested a format that isn't json -apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation -apierror.flow.410=Gone - The resource requested has been removed from our servers -apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed +apierror.flow.404=Not Found - The specified resource could not be found. +apierror.flow.405=Method Not Allowed - You tried to access a resource with an invalid method. +apierror.flow.406=Not Acceptable - You requested a format that isn't json. +apierror.flow.409=Conflict - You tried to perform an operation that conflicts with another operation. +apierror.flow.410=Gone - The resource requested has been removed from our servers. +apierror.flow.412=Precondition Failed - A prerequisite step that was required before calling the resource had not been performed. apierror.flow.422=Unprocessable Entity - The request format was valid, however one or more values were incorrect. apierror.flow.429=Too Many Requests - Too many requests may occur if an abnormal number of requests occur. apierror.flow.500=Internal Server Error - We had a problem with our server. Try again later. apierror.flow.503=Service Unavailable - We're temporarily offline for maintenance. Please try again later. apierror.flow.524=A timeout occurred -apierror.token.conflict=Invalid Payment Token‚ something went wrong‚ please try again! - -afterpay.api.pending=Your payment is pending. -afterpay.api.error=An error occurred using Clearpay -afterpay.api.cancelled=Your payment has been cancelled -afterpay.api.declined=Your payment has been declined +apierror.flow.invalid=There is an issue placing your Order. Your cart might have been changed. +afterpay.api.cancelled=Your payment has been cancelled. +afterpay.api.declined=Your payment has been declined. terms.conditions.label=Clearpay Terms & Conditions -payments.label=or make 4 interest-free payments of -learn.more.label=More info -with.label= fortnightly with -terms.link.label=Click here for complete terms. -terms.link.label.us=You must be over 18, a resident of the U.S and meet additional eligibility criteria to qualify. Late fees apply. -terms.link.us=Click here for complete terms. minimum.threshold.message=Clearpay is available for orders over {0} -maximum.threshold.message=The item is unavailable with redirect.notification=Redirecting to Clearpay Payment Page. redirect.message=Please wait... -billing.logo=Clearpay +dummy.email.id=test@clearpay.com -checkout.content.terms=Terms and conditions -checkout.content.redirect.label=You will be redirected to Clearpay when you confirm your order +checkout.content.redirect.label=You will be redirected to Clearpay when you confirm your order. checkout.content.intro.text=Pay in expresscheckout.error.multidestination=Clearpay Express Checkout unavailable for your cart (multiple destinations). Please proceed through normal checkout. expresscheckout.error.gettoken=Unable to get token. expresscheckout.error.emptycart=Cart is empty. expresscheckout.error.invalidsession=Invalid session. Please try again. -expresscheckout.error.checkout=There was a problem with the Order. Please try again. expresscheckout.error.amountMismatch=Amount returned by Afterpay did not match expected amount. +expresscheckout.error.checkout=There was a problem with the Order. Please try again. expresscheckout.error.disabled=Clearpay Express Checkout not enabled. expresscheckout.error.notfinalizeflow=Not in express checkout finalize flow. expresscheckout.error.paymentinvalidsession=Invalid session. Unable to confirm order. diff --git a/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_es_ES.properties b/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_es_ES.properties index 9f34ecd..7ec929c 100644 --- a/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_es_ES.properties +++ b/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_es_ES.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Términos y condiciones -checkout.content.redirect.label=Serás redirigido a la plataforma de Clearpay para completar tu información de pago. -checkout.content.intro.text=Paga en \ No newline at end of file +apierror.flow.default=¡Uy! Parece que ha habido un problema. Si el error persiste, por favor háznoslo saber, ¡estaremos encantados de ayudarte! +apierror.flow.402=El pago con Clearpay ha sido rechazado. Por favor selecciona un método de pago alternativo +redirect.notification=Redirigiendo a la página de pago de Clearpay +redirect.message=Por favor, espera +terms.conditions.label=Términos y condiciones de Clearpay +checkout.content.redirect.label=Serás redirigido a Clearpay cuando confirmes el pedido +checkout.content.intro.text=Paga en +minimum.threshold.message=Clearpay está disponible para pedidos superiores a {0} +afterpay.api.declined=Tu pago ha sido rechazado +afterpay.api.cancelled=Tu pago ha sido cancelado diff --git a/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_fr_FR.properties b/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_fr_FR.properties index 1ac8f22..1b9483f 100644 --- a/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_fr_FR.properties +++ b/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_fr_FR.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Conditions générales +apierror.flow.default=Oops! On dirait qu’on a eu un probleme. Si le probleme persiste, veuillez nous en informer, nous serons ravis de vous aider +apierror.flow.402=Paiement Clearpay refusé. Merci de sélectionner un mode de paiement alternatif +redirect.notification=Redirection vers la page de paiement de Clearpay +redirect.message=S.V.P attendre... +terms.conditions.label=Termes et conditions Clearpay checkout.content.redirect.label=Vous allez être redirigé vers Clearpay pour renseigner vos informations de paiement. -checkout.content.intro.text=Payez en \ No newline at end of file +checkout.content.intro.text=Payez en +minimum.threshold.message=Clearpay est disponible pour les commandes supérieures a {0} +afterpay.api.declined=Votre paiement a été refusé +afterpay.api.cancelled=Votre paiement a été annulé diff --git a/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_it_IT.properties b/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_it_IT.properties index 2da0c31..dea3777 100644 --- a/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_it_IT.properties +++ b/cartridges/int_afterpay_sg/cartridge/templates/resources/clearpay_it_IT.properties @@ -1,3 +1,10 @@ -checkout.content.terms=Termini&Condizioni +apierror.flow.default=Ops! Sembra che abbiamo avuto un problema. Se il problema persiste, faccelo sapere, saremo felici di aiutarti +apierror.flow.402=Il pagamento Clearpay rifiuta. Seleziona un metodo di pagamento alternativo +redirect.notification=Reindirizzamento alla pagina di pagamento Clearpay +redirect.message=Attendere prego... +terms.conditions.label=Termini e condizioni Clearpay checkout.content.redirect.label=Verrai reindirizzato alla piattaforma Clearpay per completare il modulo con le informazioni relative al pagamento. -checkout.content.intro.text=Paga in \ No newline at end of file +checkout.content.intro.text=Paga in +minimum.threshold.message=Clearpay e disponibile per ordini superiori {0} +afterpay.api.declined=Il tuo pagamento è stato rifiutato +afterpay.api.cancelled=Il tuo pagamento è stato annullato diff --git a/documentation/Afterpay V23.1.0 Integration Guide SiteGenesis.docx b/documentation/Afterpay V23.1.0 Integration Guide SiteGenesis.docx deleted file mode 100644 index 7ac5cac..0000000 Binary files a/documentation/Afterpay V23.1.0 Integration Guide SiteGenesis.docx and /dev/null differ diff --git a/documentation/Afterpay V23.1.0 Integration Guide _ SFRA.docx b/documentation/Afterpay V23.1.0 Integration Guide _ SFRA.docx deleted file mode 100644 index 006b7f9..0000000 Binary files a/documentation/Afterpay V23.1.0 Integration Guide _ SFRA.docx and /dev/null differ diff --git a/documentation/Afterpay V23.2.0 Integration Guide SiteGenesis.docx b/documentation/Afterpay V23.2.0 Integration Guide SiteGenesis.docx new file mode 100644 index 0000000..fcd1011 Binary files /dev/null and b/documentation/Afterpay V23.2.0 Integration Guide SiteGenesis.docx differ diff --git a/documentation/Afterpay V23.2.0 Integration Guide _ SFRA.docx b/documentation/Afterpay V23.2.0 Integration Guide _ SFRA.docx new file mode 100644 index 0000000..05e63a4 Binary files /dev/null and b/documentation/Afterpay V23.2.0 Integration Guide _ SFRA.docx differ diff --git a/documentation/Upgrade Guide/Afterpay V23.1.0 Upgrade Guide SFRA.docx b/documentation/Upgrade Guide/Afterpay V23.1.0 Upgrade Guide SFRA.docx deleted file mode 100644 index ebd789c..0000000 Binary files a/documentation/Upgrade Guide/Afterpay V23.1.0 Upgrade Guide SFRA.docx and /dev/null differ diff --git a/documentation/Upgrade Guide/Afterpay V23.1.0 Upgrade Guide SiteGenesis.docx b/documentation/Upgrade Guide/Afterpay V23.1.0 Upgrade Guide SiteGenesis.docx deleted file mode 100644 index d7117b8..0000000 Binary files a/documentation/Upgrade Guide/Afterpay V23.1.0 Upgrade Guide SiteGenesis.docx and /dev/null differ diff --git a/documentation/Upgrade Guide/Afterpay V23.2.0 Upgrade Guide SFRA.docx b/documentation/Upgrade Guide/Afterpay V23.2.0 Upgrade Guide SFRA.docx new file mode 100644 index 0000000..1db482c Binary files /dev/null and b/documentation/Upgrade Guide/Afterpay V23.2.0 Upgrade Guide SFRA.docx differ diff --git a/documentation/Upgrade Guide/Afterpay V23.2.0 Upgrade Guide SiteGenesis.docx b/documentation/Upgrade Guide/Afterpay V23.2.0 Upgrade Guide SiteGenesis.docx new file mode 100644 index 0000000..794b28e Binary files /dev/null and b/documentation/Upgrade Guide/Afterpay V23.2.0 Upgrade Guide SiteGenesis.docx differ diff --git a/documentation/Upgrade Guide/Cash App Pay/Cash App Pay V23.2.0 Upgrade Guide SFRA.docx b/documentation/Upgrade Guide/Cash App Pay/Cash App Pay V23.2.0 Upgrade Guide SFRA.docx new file mode 100644 index 0000000..09adc3d Binary files /dev/null and b/documentation/Upgrade Guide/Cash App Pay/Cash App Pay V23.2.0 Upgrade Guide SFRA.docx differ diff --git a/documentation/Upgrade Guide/Cash App Pay/Cash App Pay V23.2.0 Upgrade Guide SiteGenesis.docx b/documentation/Upgrade Guide/Cash App Pay/Cash App Pay V23.2.0 Upgrade Guide SiteGenesis.docx new file mode 100644 index 0000000..3d2dbf9 Binary files /dev/null and b/documentation/Upgrade Guide/Cash App Pay/Cash App Pay V23.2.0 Upgrade Guide SiteGenesis.docx differ diff --git a/metadata/afterpay-meta-import/meta/system-objecttype-extensions.xml b/metadata/afterpay-meta-import/meta/system-objecttype-extensions.xml index 0972e7b..0232873 100644 --- a/metadata/afterpay-meta-import/meta/system-objecttype-extensions.xml +++ b/metadata/afterpay-meta-import/meta/system-objecttype-extensions.xml @@ -9,12 +9,23 @@ false false + + CashAppPay Payment Method + Determines if this is an CashAppPay order + boolean + false + false + Afterpay + + Cash App Pay + + @@ -217,6 +228,12 @@ boolean false false + + + Enable Cash App Pay + boolean + false + false Enable Express Checkout @@ -268,6 +285,7 @@ Integration Afterpay + diff --git a/metadata/afterpay-meta-import/services.xml b/metadata/afterpay-meta-import/services.xml index ae32e68..d216a7a 100644 --- a/metadata/afterpay-meta-import/services.xml +++ b/metadata/afterpay-meta-import/services.xml @@ -24,7 +24,19 @@ ******** - + + https://global-api-sandbox.afterpay.com/v2/ + + ******** + + + + https://global-api-sandbox.afterpay.com/v2/ + + ******** + + + https://global-api-sandbox.afterpay.com/v2/ ******** @@ -90,7 +102,29 @@ afterpay.credentials.US.v2 - + + HTTP + true + Clearpay + true + false + false + afterpay.profile + clearpay.credentials.ES.v2 + + + + HTTP + true + Clearpay + true + false + false + afterpay.profile + clearpay.credentials.IT.v2 + + + HTTP true Clearpay @@ -98,7 +132,7 @@ false false afterpay.profile - clearpay.credentials.EU.v2 + clearpay.credentials.FR.v2 diff --git a/metadata/afterpay-meta-import/sites/RefArch/payment-methods.xml b/metadata/afterpay-meta-import/sites/RefArch/payment-methods.xml index 2293e7d..bb2e98d 100644 --- a/metadata/afterpay-meta-import/sites/RefArch/payment-methods.xml +++ b/metadata/afterpay-meta-import/sites/RefArch/payment-methods.xml @@ -63,4 +63,23 @@ + + + Cash App Pay + cashapppay-logomark1x.png + true + CASHAPP_CREDIT + + + + + USD + + + + 0.03 + 1000 + + + diff --git a/metadata/afterpay-meta-import/sites/RefArch/payment-processors.xml b/metadata/afterpay-meta-import/sites/RefArch/payment-processors.xml index cc9465c..2369df5 100644 --- a/metadata/afterpay-meta-import/sites/RefArch/payment-processors.xml +++ b/metadata/afterpay-meta-import/sites/RefArch/payment-processors.xml @@ -8,4 +8,12 @@ + + + + + + + + diff --git a/metadata/afterpay-meta-import/sites/RefArch/preferences.xml b/metadata/afterpay-meta-import/sites/RefArch/preferences.xml index b6f8c75..0ef357f 100644 --- a/metadata/afterpay-meta-import/sites/RefArch/preferences.xml +++ b/metadata/afterpay-meta-import/sites/RefArch/preferences.xml @@ -15,6 +15,7 @@ false DIRECT_CAPTURE false + false true integrated true diff --git a/metadata/afterpay-meta-import/sites/RefArchGlobal/payment-methods.xml b/metadata/afterpay-meta-import/sites/RefArchGlobal/payment-methods.xml index e99d692..1ae3c67 100644 --- a/metadata/afterpay-meta-import/sites/RefArchGlobal/payment-methods.xml +++ b/metadata/afterpay-meta-import/sites/RefArchGlobal/payment-methods.xml @@ -63,4 +63,23 @@ + + + Cash App Pay + cashapppay-logomark1x.png + true + CASHAPP_CREDIT + + + + + USD + + + + 0.03 + 1000 + + + diff --git a/metadata/afterpay-meta-import/sites/RefArchGlobal/payment-processors.xml b/metadata/afterpay-meta-import/sites/RefArchGlobal/payment-processors.xml index cc9465c..4af8e1b 100644 --- a/metadata/afterpay-meta-import/sites/RefArchGlobal/payment-processors.xml +++ b/metadata/afterpay-meta-import/sites/RefArchGlobal/payment-processors.xml @@ -8,4 +8,12 @@ + + + + + + + + diff --git a/metadata/afterpay-meta-import/sites/RefArchGlobal/preferences.xml b/metadata/afterpay-meta-import/sites/RefArchGlobal/preferences.xml index fadacda..e6aaa41 100644 --- a/metadata/afterpay-meta-import/sites/RefArchGlobal/preferences.xml +++ b/metadata/afterpay-meta-import/sites/RefArchGlobal/preferences.xml @@ -30,19 +30,19 @@ }, "ES": { "brand": "clearpay", - "service": "clearpay.service.EU.v2", + "service": "clearpay.service.ES.v2", "javaScriptUrl": "https://merchant-tools.sandbox.clearpay.com/clearpay.js", "learnMoreUrl": "https://www.clearpay.com/es/terms/" }, "FR": { "brand": "clearpay", - "service": "clearpay.service.EU.v2", + "service": "clearpay.service.FR.v2", "javaScriptUrl": "https://merchant-tools.sandbox.clearpay.com/clearpay.js", "learnMoreUrl": "https://www.clearpay.com/fr/terms/" }, "IT": { "brand": "clearpay", - "service": "clearpay.service.EU.v2", + "service": "clearpay.service.IT.v2", "javaScriptUrl": "https://merchant-tools.sandbox.clearpay.com/clearpay.js", "learnMoreUrl": "https://www.clearpay.com/it/terms/" }, @@ -57,6 +57,7 @@ false DIRECT_CAPTURE false + false true integrated true diff --git a/package.json b/package.json index 76d45cb..a492244 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Afterpay", - "version": "23.1.0", + "version": "23.2.0-beta.1", "description": "Afterpay cartridge", "main": "index.js", "engines": { diff --git a/cartridges/int_afterpay_sg/cartridge/scss/_afterpay.scss b/reference/_afterpay.scss similarity index 96% rename from cartridges/int_afterpay_sg/cartridge/scss/_afterpay.scss rename to reference/_afterpay.scss index 7a8ccfb..85242a5 100644 --- a/cartridges/int_afterpay_sg/cartridge/scss/_afterpay.scss +++ b/reference/_afterpay.scss @@ -21,8 +21,18 @@ .afterpay-image { vertical-align: middle; - width: 7em; - margin: 5px 0; + width: 10em; + margin: 0; +} + +.clearpay-image { + vertical-align: middle; + width: 10em; + margin: 0; +} + +.cashapppay-image { + width: 10em; } .pdp-afterpay-message { @@ -135,7 +145,7 @@ .redirect-text { text-align: center; margin-top: 2.1875em; - font-size: 1.375em; + font-size: 2.375em; } .checkout-afterpay-message {