diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/cms/AdyenAccCartExpressCheckoutComponentController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/cms/AdyenAccCartExpressCheckoutComponentController.java new file mode 100644 index 000000000..678a7cae3 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/cms/AdyenAccCartExpressCheckoutComponentController.java @@ -0,0 +1,35 @@ +package com.adyen.v6.controllers.cms; + +import com.adyen.service.exception.ApiException; +import com.adyen.v6.facades.AdyenCheckoutFacade; +import com.adyen.v6.facades.AdyenExpressCheckoutFacade; +import com.adyen.v6.model.contents.components.AdyenAccExpressCheckoutCartPageComponentModel; +import de.hybris.platform.addonsupport.controllers.cms.AbstractCMSAddOnComponentController; +import de.hybris.platform.order.exceptions.CalculationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletRequest; + +@Controller(AdyenAccExpressCheckoutCartPageComponentModel._TYPECODE + "Controller") +@RequestMapping(value = "/view/" + AdyenAccExpressCheckoutCartPageComponentModel._TYPECODE + "Controller") +public class AdyenAccCartExpressCheckoutComponentController extends AbstractCMSAddOnComponentController { + + @Autowired + private AdyenCheckoutFacade adyenCheckoutFacade; + + @Autowired + private AdyenExpressCheckoutFacade adyenExpressCheckoutFacade; + + @Override + protected void fillModel(final HttpServletRequest request, final Model model, final AdyenAccExpressCheckoutCartPageComponentModel component) { + try { + adyenExpressCheckoutFacade.removeDeliveryModeFromSessionCart(); + adyenCheckoutFacade.initializeApplePayExpressCartPageData(model); + } catch (ApiException | CalculationException e) { + throw new RuntimeException(e); + } + } +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/cms/AdyenAccProductExpressCheckoutComponentController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/cms/AdyenAccProductExpressCheckoutComponentController.java new file mode 100644 index 000000000..528ae66a1 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/cms/AdyenAccProductExpressCheckoutComponentController.java @@ -0,0 +1,41 @@ +package com.adyen.v6.controllers.cms; + +import com.adyen.service.exception.ApiException; +import com.adyen.v6.facades.AdyenCheckoutFacade; +import com.adyen.v6.model.contents.components.AdyenAccExpressCheckoutProductPageComponentModel; +import de.hybris.platform.acceleratorservices.data.RequestContextData; +import de.hybris.platform.addonsupport.controllers.cms.AbstractCMSAddOnComponentController; +import de.hybris.platform.commercefacades.product.ProductFacade; +import de.hybris.platform.commercefacades.product.ProductOption; +import de.hybris.platform.commercefacades.product.data.ProductData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; + +@Controller(AdyenAccExpressCheckoutProductPageComponentModel._TYPECODE + "Controller") +@RequestMapping(value = "/view/" + AdyenAccExpressCheckoutProductPageComponentModel._TYPECODE + "Controller") +public class AdyenAccProductExpressCheckoutComponentController extends AbstractCMSAddOnComponentController { + + @Autowired + private AdyenCheckoutFacade adyenCheckoutFacade; + + @Autowired + private ProductFacade productFacade; + + @Override + protected void fillModel(final HttpServletRequest request, final Model model, final AdyenAccExpressCheckoutProductPageComponentModel component) { + try { + RequestContextData requestContextData = getRequestContextData(request); + requestContextData.getProduct(); + final ProductData productData = productFacade.getProductForCodeAndOptions(requestContextData.getProduct().getCode(), Arrays.asList(ProductOption.BASIC, ProductOption.PRICE)); + + adyenCheckoutFacade.initializeApplePayExpressPDPData(model, productData); + } catch (ApiException e) { + throw new RuntimeException(e); + } + } +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/expressCheckoutConfig.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/expressCheckoutConfig.tag new file mode 100644 index 000000000..b14f22313 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/expressCheckoutConfig.tag @@ -0,0 +1,48 @@ +<%@ taglib prefix="adyen" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> +<%@ attribute name="pageType" required="true" type="java.lang.String"%> + + + + + + + + + + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/cms/adyenaccexpresscheckoutcartpagecomponent.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/cms/adyenaccexpresscheckoutcartpagecomponent.jsp new file mode 100644 index 000000000..b0d28fa19 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/cms/adyenaccexpresscheckoutcartpagecomponent.jsp @@ -0,0 +1,14 @@ +<%@ page trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="adyen" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> + + + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/cms/adyenaccexpresscheckoutproductpagecomponent.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/cms/adyenaccexpresscheckoutproductpagecomponent.jsp new file mode 100644 index 000000000..33d2fb0ba --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/cms/adyenaccexpresscheckoutproductpagecomponent.jsp @@ -0,0 +1,8 @@ +<%@ page trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="adyen" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> + + + +
+
diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen_express_checkout.js b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen_express_checkout.js index 271d2d910..ac79f6499 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen_express_checkout.js +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen_express_checkout.js @@ -30,8 +30,14 @@ var AdyenExpressCheckoutHybris = (function() { console.error("Checkout error occured"); }, }; - - return await AdyenCheckout(configuration); + console.log(configuration) + return await AdyenWeb.AdyenCheckout(configuration); + }, + initExpressCheckout: async function (params, config) { + var checkoutPromise = this.initiateCheckout(config); + checkoutPromise.then((checkout) => { + this.initiateGooglePayExpress(checkout, params) + }); }, initiateApplePayExpress: async function(params, config) { var checkoutPromise = this.initiateCheckout(config); @@ -92,8 +98,8 @@ var AdyenExpressCheckoutHybris = (function() { // empty to block session flow, submit logic done in onAuthorized }, onAuthorized: (resolve, reject, event) => { - var data = this.prepareData(event); - this.makePayment(data, resolve, reject); + var data = this.prepareDataApple(event); + this.makePayment(data, this.getAppleUrl(), resolve, reject); } }); applePayComponent.isAvailable() @@ -106,9 +112,135 @@ var AdyenExpressCheckoutHybris = (function() { }); }) }, - makePayment: function(data, resolve, reject) { + initiateGooglePayExpress: function (checkout, params) { + const { + amount, + amountDecimal, + countryCode, + pageType, + productCode + } = params; + + this.adyenConfig.pageType = pageType; + this.adyenConfig.productCode = productCode; + + const googlePayNodes = document.getElementsByClassName('adyen-google-pay-button'); + + const googlePayConfig = { + + // Step 2: Set the callback intents. + buttonSizeMode: "fill", + buttonType: "checkout", + + callbackIntents: ['SHIPPING_ADDRESS'], + + // Step 3: Set shipping configurations. + + shippingAddressRequired: true, + emailRequired: true, + + shippingAddressParameters: { + allowedCountryCodes: [], + phoneNumberRequired: false + }, + + // Shipping options configurations. + shippingOptionRequired: false, + + // Step 4: Pass the default shipping options. + + // shippingOptions: { + // defaultSelectedOptionId: 'shipping-001', + // shippingOptions: [ + // { + // id: 'shipping-001', + // label: '$0.00: Free shipping', + // description: 'Free shipping: delivered in 10 business days.' + // }, + // { + // id: 'shipping-002', + // label: '$1.99: Standard shipping', + // description: 'Standard shipping: delivered in 3 business days.' + // }, + // ] + // }, + + // Step 5: Set the transaction information. + + //Required for v6.0.0 or later. + isExpress: true, + + + transactionInfo: { + countryCode: countryCode, + currencyCode: amount.currency, + totalPriceStatus: 'FINAL', + totalPrice: amountDecimal, + totalPriceLabel: 'Total' + }, + + // Step 6: Update the payment data. + + paymentDataCallbacks: { + onPaymentDataChanged(intermediatePaymentData) { + return new Promise(async resolve => { + const { + callbackTrigger, + shippingAddress, + shippingOptionData + } = intermediatePaymentData; + const paymentDataRequestUpdate = {}; + + // Validate the country/region and address selection. + if (shippingAddress.countryCode !== 'US' && shippingAddress.countryCode !== 'BR') { + paymentDataRequestUpdate.error = { + reason: 'SHIPPING_ADDRESS_UNSERVICEABLE', + message: 'Cannot ship to the selected address', + intent: 'SHIPPING_ADDRESS' + }; + } + + // If it initializes or changes the shipping address, calculate the shipping options and transaction info. + if (callbackTrigger === 'INITIALIZE' || callbackTrigger === 'SHIPPING_ADDRESS') { + // paymentDataRequestUpdate.newShippingOptionParameters = await fetchNewShippingOptions(shippingAddress.countryCode); + // paymentDataRequestUpdate.newTransactionInfo = calculateNewTransactionInfo(/* ... */); + } + + // If SHIPPING_OPTION changes, calculate the new shipping amount. + if (callbackTrigger === 'SHIPPING_OPTION') { + // paymentDataRequestUpdate.newTransactionInfo = calculateNewTransactionInfo(/* ... */); + } + + resolve(paymentDataRequestUpdate); + }); + } + }, + + // Step 7: Configure the callback to get the shopper's information. + + onAuthorized: (paymentData) => { + this.makePayment(this.prepareDataGoogle(paymentData), this.getGoogleUrl()) + }, + onError: function (error) { + console.log(error) + } + } + + for (let googlePayNode of googlePayNodes) { + let googlePayComponent = new AdyenWeb.GooglePay(checkout, googlePayConfig); + googlePayComponent.isAvailable() + .then(function () { + googlePayComponent.mount(googlePayNode); + }) + .catch(function (e) { + // Google Pay is not available + console.log('Something went wrong trying to mount the Google Pay component'); + }); + } + }, + makePayment: function(data, url, resolve = ()=>{}, reject = ()=>{}) { $.ajax({ - url: this.getUrl(), + url: url, type: "POST", data: JSON.stringify(data), contentType: "application/json; charset=utf-8", @@ -147,7 +279,8 @@ var AdyenExpressCheckoutHybris = (function() { } document.querySelector("#handleComponentResultForm").submit(); }, - prepareData: function(event) { + prepareDataApple: function(event) { + //TODO: Refactor as google data if (this.adyenConfig.pageType === 'PDP') { return { productCode: this.adyenConfig.productCode, @@ -192,7 +325,39 @@ var AdyenExpressCheckoutHybris = (function() { console.error('unknown page type') return {}; }, - getUrl: function() { + prepareDataGoogle: function(paymentData) { + const baseData = { + googlePayToken: paymentData.authorizedEvent.paymentMethodData.tokenizationData.token, + googlePayCardNetwork: paymentData.authorizedEvent.paymentMethodData.info.cardNetwork, + addressData: { + email: paymentData.authorizedEvent.email, + firstName: paymentData.deliveryAddress.firstName, + // lastName: paymentData.payment.shippingContact.familyName, + line1: paymentData.deliveryAddress.street, + line2: paymentData.deliveryAddress.houseNumberOrName, + postalCode: paymentData.deliveryAddress.postalCode, + town: paymentData.deliveryAddress.city, + country: { + isocode: paymentData.deliveryAddress.country, + }, + region: { + isocodeShort: paymentData.deliveryAddress.stateOrProvince + } + } + } + if (this.adyenConfig.pageType === 'PDP') { + return { + productCode: this.adyenConfig.productCode, + ...baseData + } + } + if (this.adyenConfig.pageType === 'cart') { + return baseData; + } + console.error('unknown page type') + return {}; + }, + getAppleUrl: function() { if (this.adyenConfig.pageType === 'PDP') { return ACC.config.encodedContextPath + '/expressCheckout/applePayPDP' } @@ -201,6 +366,16 @@ var AdyenExpressCheckoutHybris = (function() { } console.error('unknown page type') return null; + }, + getGoogleUrl: function() { + if (this.adyenConfig.pageType === 'PDP') { + return ACC.config.encodedContextPath + '/expressCheckout/googlePayPDP' + } + if (this.adyenConfig.pageType === 'cart') { + return ACC.config.encodedContextPath + '/expressCheckout/googlePayCart' + } + console.error('unknown page type') + return null; } } })(); \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon-items.xml b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon-items.xml index 19dc5fa6c..dabc6f54e 100644 --- a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon-items.xml +++ b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon-items.xml @@ -19,5 +19,13 @@ xsi:noNamespaceSchemaLocation="items.xsd"> + + Represents express checkout options for product page. + + + Represents express checkout options for product page. + diff --git a/adyenv6b2ccheckoutaddon/resources/impex/projectdata-cms-config.impex b/adyenv6b2ccheckoutaddon/resources/impex/projectdata-cms-config.impex index ab834040c..4ae5791b8 100644 --- a/adyenv6b2ccheckoutaddon/resources/impex/projectdata-cms-config.impex +++ b/adyenv6b2ccheckoutaddon/resources/impex/projectdata-cms-config.impex @@ -1,10 +1,23 @@ -$contentCatalog=electronicsContentCatalog -$contentCVS=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),CatalogVersion.version[default=Staged])[default=$contentCatalog:Staged] -$contentCVO=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),CatalogVersion.version[default=Online])[default=$contentCatalog:Online] +$contentCatalog = electronicsContentCatalog +$contentCVS = catalogVersion(CatalogVersion.catalog(Catalog.id[default = $contentCatalog]), CatalogVersion.version[default = Staged])[default = $contentCatalog:Staged] +$contentCVO = catalogVersion(CatalogVersion.catalog(Catalog.id[default = $contentCatalog]), CatalogVersion.version[default = Online])[default = $contentCatalog:Online] -INSERT_UPDATE JspIncludeComponent;uid[unique=true];page;$contentCVS[unique=true] - ;CartComponent;/WEB-INF/views/responsive/pages/cart/cartDisplay.jsp +INSERT_UPDATE JspIncludeComponent; uid[unique = true]; page; $contentCVS[unique = true] + ; CartComponent ; /WEB-INF/views/responsive/pages/cart/cartDisplay.jsp -INSERT_UPDATE JspIncludeComponent;uid[unique=true];page;$contentCVO[unique=true] - ;CartComponent;/WEB-INF/views/responsive/pages/cart/cartDisplay.jsp \ No newline at end of file +INSERT_UPDATE JspIncludeComponent; uid[unique = true]; page; $contentCVO[unique = true] + ; CartComponent ; /WEB-INF/views/responsive/pages/cart/cartDisplay.jsp + +INSERT_UPDATE ContentSlot; $contentCVS[unique = true]; uid[unique = true]; cmsComponents(&componentRef)[mode = merge] + ; ; AddToCartSlot ; AccAdyenProductExpressCheckout + +INSERT_UPDATE AdyenAccExpressCheckoutProductPageComponent; $contentCVS[unique = true]; uid[unique = true] ; name ; &componentRef + ; ; AccAdyenProductExpressCheckout ; Adyen Accelerator Product Page Express Checkout ; AccAdyenProductExpressCheckout + +INSERT_UPDATE ContentSlot; $contentCVS[unique = true]; uid[unique = true] ; cmsComponents($contentCVS, uid) + ; ; TopContent-cartPage ; AccAdyenCartExpressCheckout,CartComponent + ; ; BottomContentSlot-cartPage ; CheckoutComponent,AccAdyenCartExpressCheckout,CartSuggestions + +INSERT_UPDATE AdyenAccExpressCheckoutCartPageComponent; $contentCVS[unique = true]; uid[unique = true] ; name ; &componentRef + ; ; AccAdyenCartExpressCheckout ; Adyen Accelerator Cart Page Express Checkout ; AccAdyenCartExpressCheckout diff --git a/adyenv6b2ccheckoutaddon/src/com/adyen/v6/jalo/contents/components/AdyenAccExpressCheckoutCartPageComponent.java b/adyenv6b2ccheckoutaddon/src/com/adyen/v6/jalo/contents/components/AdyenAccExpressCheckoutCartPageComponent.java new file mode 100644 index 000000000..00ea25c89 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/src/com/adyen/v6/jalo/contents/components/AdyenAccExpressCheckoutCartPageComponent.java @@ -0,0 +1,25 @@ +package com.adyen.v6.jalo.contents.components; + +import de.hybris.platform.jalo.Item; +import de.hybris.platform.jalo.JaloBusinessException; +import de.hybris.platform.jalo.SessionContext; +import de.hybris.platform.jalo.type.ComposedType; +import org.apache.log4j.Logger; + +public class AdyenAccExpressCheckoutCartPageComponent extends GeneratedAdyenAccExpressCheckoutCartPageComponent +{ + @SuppressWarnings("unused") + private static final Logger LOG = Logger.getLogger( AdyenAccExpressCheckoutCartPageComponent.class.getName() ); + + @Override + protected Item createItem(final SessionContext ctx, final ComposedType type, final ItemAttributeMap allAttributes) throws JaloBusinessException + { + // business code placed here will be executed before the item is created + // then create the item + final Item item = super.createItem( ctx, type, allAttributes ); + // business code placed here will be executed after the item was created + // and return the item + return item; + } + +} diff --git a/adyenv6b2ccheckoutaddon/src/com/adyen/v6/jalo/contents/components/AdyenAccExpressCheckoutProductPageComponent.java b/adyenv6b2ccheckoutaddon/src/com/adyen/v6/jalo/contents/components/AdyenAccExpressCheckoutProductPageComponent.java new file mode 100644 index 000000000..ba36119b6 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/src/com/adyen/v6/jalo/contents/components/AdyenAccExpressCheckoutProductPageComponent.java @@ -0,0 +1,25 @@ +package com.adyen.v6.jalo.contents.components; + +import de.hybris.platform.jalo.Item; +import de.hybris.platform.jalo.JaloBusinessException; +import de.hybris.platform.jalo.SessionContext; +import de.hybris.platform.jalo.type.ComposedType; +import org.apache.log4j.Logger; + +public class AdyenAccExpressCheckoutProductPageComponent extends GeneratedAdyenAccExpressCheckoutProductPageComponent +{ + @SuppressWarnings("unused") + private static final Logger LOG = Logger.getLogger( AdyenAccExpressCheckoutProductPageComponent.class.getName() ); + + @Override + protected Item createItem(final SessionContext ctx, final ComposedType type, final ItemAttributeMap allAttributes) throws JaloBusinessException + { + // business code placed here will be executed before the item is created + // then create the item + final Item item = super.createItem( ctx, type, allAttributes ); + // business code placed here will be executed after the item was created + // and return the item + return item; + } + +} diff --git a/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenCheckoutFacade.java b/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenCheckoutFacade.java index 09a8d50db..ce1c990ed 100644 --- a/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenCheckoutFacade.java +++ b/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenCheckoutFacade.java @@ -222,6 +222,7 @@ public class DefaultAdyenCheckoutFacade implements AdyenCheckoutFacade { public static final String MODEL_CONNECTED_TERMINAL_LIST = "connectedTerminalList"; public static final String MODEL_ENVIRONMENT_MODE = "environmentMode"; public static final String MODEL_AMOUNT = "amount"; + public static final String MODEL_AMOUNT_DECIMAL= "amountDecimal"; public static final String MODEL_IMMEDIATE_CAPTURE = "immediateCapture"; public static final String MODEL_PAYPAL_MERCHANT_ID = "paypalMerchantId"; public static final String MODEL_COUNTRY_CODE = "countryCode"; @@ -1093,6 +1094,7 @@ protected void initializeApplePayExpressDataInternal(BigDecimal amountValue, Str model.addAttribute(MODEL_MERCHANT_ACCOUNT, adyenMerchantAccountStrategy.getWebMerchantAccount()); model.addAttribute(SESSION_DATA, getAdyenSessionData(amount)); model.addAttribute(MODEL_AMOUNT, amount); + model.addAttribute(MODEL_AMOUNT_DECIMAL, amountValue); model.addAttribute(MODEL_DF_URL, getAdyenPaymentService().getDeviceFingerprintUrl()); model.addAttribute(MODEL_CHECKOUT_SHOPPER_HOST, getCheckoutShopperHost()); }