diff --git a/README.md b/README.md index d1e9a580b..fac115681 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ Required for the checkout: ``` +Required for the notifications: +``` + +``` Additionally, required when using yacceleratorordermanagement (b2c_acc_oms recipe): ``` @@ -33,9 +37,9 @@ Additionally, required when using yacceleratorfulfilment (b2c_acc recipe): ``` -### 3. Modify local.properties +### 3. Modify local.properties -Modify config/local.properties file: +Modify config/local.properties file: append ,/[^/]+(/[^?]*)+(adyen-response)$,/adyen(/[^?]*)+$ to the value of csrf.allowed.url.patterns ### 4. Build @@ -56,12 +60,11 @@ Please make sure your merchant has Variant true in API and responses section so ### Credit Cards -Credit Card payments are supported using [Client Side Encryption](https://docs.adyen.com/support/payment-glossary/client-side-encryption-cse). +Credit Card payments are supported using Checkout Components. -### Klarna +### Ratepay -Klarna is supported via Adyen API. -Requires shopper data listed in: https://developers.klarna.com/en/se/kpm/test-credentials +Ratepay is supported via Adyen API. ### Boleto @@ -79,7 +82,7 @@ More details can be found here: https://docs.adyen.com/developers/payment-method ### Other alternative payment methods -Supported via Adyen [Hosted Payment Pages](https://docs.adyen.com/developers/products-and-subscriptions/hosted-payment-pages). +Supported via Adyen Checkout. ## Usage with OCC @@ -109,7 +112,7 @@ For Credit Card payments - it expects encrypted card holder data obtained from y For Stored Cards payments - selected Adyen recurringReference of the card and encrypted cvc For Boleto payments - social security number - + 3. OrderData authorisePayment(CartData cartData) throws Exception; @@ -124,13 +127,18 @@ It returns an instance of OrderWSDTO obtained from OrderData of the placed order For Boleto, it will contain the pdf url, the base64 encoded data, expiration date and due date https://docs.adyen.com/developers/payment-methods/boleto-bancario/boleto-payment-request + ## 3DS2 configuration + By default 3DS2 is disabled. If you want to enable 3DS2 in your system, please set following property in local.properties file, build your environment and restart the server. +``` +is3DS2allowed = true +``` ## Documentation https://docs.adyen.com/developers/plugins/hybris - + ## Support You can create issues on our Magento Repository. In case of specific problems with your account, please contact support@adyen.com. - + ## License MIT license. For more information, see the LICENSE file. diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/constants/AdyenControllerConstants.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/constants/AdyenControllerConstants.java index 3b691a568..5225a374f 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/constants/AdyenControllerConstants.java +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/constants/AdyenControllerConstants.java @@ -24,7 +24,6 @@ public interface AdyenControllerConstants { String ADDON_PREFIX = "addon:/adyenv6b2ccheckoutaddon/"; String SUMMARY_CHECKOUT_PREFIX = "/checkout/multi/adyen/summary"; - String NOTIFICATION_PREFIX = "/adyen/v6/notification"; String PAYPAL_ECS_PREFIX = "/adyen/paypal-ecs"; /** @@ -42,6 +41,7 @@ interface MultiStepCheckout String SelectPaymentMethod = ADDON_PREFIX + "pages/checkout/multi/selectPaymentMethodPage"; String Validate3DSecurePaymentPage = ADDON_PREFIX + "pages/checkout/multi/3d-secure-payment-validation"; String HppPaymentPage = ADDON_PREFIX + "pages/checkout/multi/hpp-payment"; + String Validate3DS2PaymentPage = ADDON_PREFIX + "pages/checkout/multi/3ds2_payment"; } } diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenNotificationController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenNotificationController.java deleted file mode 100644 index 5e47460da..000000000 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenNotificationController.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ###### - * ###### - * ############ ####( ###### #####. ###### ############ ############ - * ############# #####( ###### #####. ###### ############# ############# - * ###### #####( ###### #####. ###### ##### ###### ##### ###### - * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### - * ###### ###### #####( ###### #####. ###### ##### ##### ###### - * ############# ############# ############# ############# ##### ###### - * ############ ############ ############# ############ ##### ###### - * ###### - * ############# - * ############ - * - * Adyen Hybris Extension - * - * Copyright (c) 2017 Adyen B.V. - * This file is open source and available under the MIT license. - * See the LICENSE file for more info. - */ -package com.adyen.v6.controllers.pages; - -import java.io.IOException; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; -import org.apache.commons.io.IOUtils; -import org.apache.log4j.Logger; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; -import com.adyen.v6.constants.AdyenControllerConstants; -import com.adyen.v6.security.AdyenNotificationAuthenticationProvider; -import com.adyen.v6.service.AdyenNotificationService; - -@Controller -@RequestMapping(value = AdyenControllerConstants.NOTIFICATION_PREFIX) -public class AdyenNotificationController { - private static final Logger LOG = Logger.getLogger(AdyenNotificationController.class); - - @Resource(name = "adyenNotificationAuthenticationProvider") - private AdyenNotificationAuthenticationProvider adyenNotificationAuthenticationProvider; - - @Resource(name = "adyenNotificationService") - private AdyenNotificationService adyenNotificationService; - - private static final String RESPONSE_ACCEPTED = "[accepted]"; - private static final String RESPONSE_NOT_ACCEPTED = "[not-accepted]"; - - @RequestMapping(value = "/json", method = RequestMethod.POST) - @ResponseBody - public String onReceive(final HttpServletRequest request) { - String requestString = null; - try { - //Parse response body by request input stream so that Spring doesn't try to deserialize - requestString = IOUtils.toString(request.getInputStream()); - } catch (IOException e) { - LOG.error(e); - return RESPONSE_NOT_ACCEPTED; - } - - LOG.debug("Received Adyen notification:" + requestString); - if (! adyenNotificationAuthenticationProvider.authenticateBasic(request)) { - throw new AccessDeniedException("Wrong credentials"); - } - - adyenNotificationService.saveNotifications(requestString); - - return RESPONSE_ACCEPTED; - } -} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepController.java index 63035096b..c21db4b6a 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepController.java +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepController.java @@ -64,7 +64,15 @@ import de.hybris.platform.site.BaseSiteService; import static com.adyen.constants.ApiConstants.Redirect.Data.MD; import static com.adyen.constants.ApiConstants.Redirect.Data.PAREQ; +import static com.adyen.constants.ApiConstants.Redirect.Data.PAYMENT_DATA; +import static com.adyen.constants.ApiConstants.ThreeDS2Property.CHALLENGE_TOKEN; +import static com.adyen.constants.ApiConstants.ThreeDS2Property.FINGERPRINT_TOKEN; +import static com.adyen.constants.ApiConstants.ThreeDS2Property.THREEDS2_CHALLENGE_TOKEN; +import static com.adyen.constants.ApiConstants.ThreeDS2Property.THREEDS2_FINGERPRINT_TOKEN; import static com.adyen.constants.BrandCodes.PAYPAL_ECS; +import static com.adyen.constants.HPPConstants.Response.SHOPPER_LOCALE; +import static com.adyen.model.checkout.PaymentsResponse.ResultCodeEnum.CHALLENGESHOPPER; +import static com.adyen.model.checkout.PaymentsResponse.ResultCodeEnum.IDENTIFYSHOPPER; import static com.adyen.model.checkout.PaymentsResponse.ResultCodeEnum.REDIRECTSHOPPER; import static com.adyen.model.checkout.PaymentsResponse.ResultCodeEnum.REFUSED; import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BOLETO; @@ -72,6 +80,8 @@ import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_ONECLICK; import static com.adyen.v6.constants.Adyenv6coreConstants.RATEPAY; import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_MULTIBANCO; +import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.MODEL_CHECKOUT_SHOPPER_HOST; +import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.MODEL_ORIGIN_KEY; @Controller @RequestMapping(value = AdyenControllerConstants.SUMMARY_CHECKOUT_PREFIX) @@ -173,9 +183,7 @@ public String placeOrder(@ModelAttribute("placeOrderForm") final PlaceOrderForm //In case of Boleto, show link to pdf if (PAYMENT_METHOD_BOLETO.equals(cartData.getAdyenPaymentMethod())) { addBoletoMessage(redirectModel, orderData.getCode()); - } - - else if (PAYMENT_METHOD_MULTIBANCO.equals(cartData.getAdyenPaymentMethod())) { + } else if (PAYMENT_METHOD_MULTIBANCO.equals(cartData.getAdyenPaymentMethod())) { addMultibancoMessage(redirectModel, orderData.getCode()); } @@ -199,6 +207,26 @@ else if (PAYMENT_METHOD_MULTIBANCO.equals(cartData.getAdyenPaymentMethod())) { if (REFUSED == paymentsResponse.getResultCode()) { errorMessage = getErrorMessageByRefusalReason(paymentsResponse.getRefusalReason()); } + if (IDENTIFYSHOPPER == paymentsResponse.getResultCode()) { + if (adyenPaymentMethod.equals(PAYMENT_METHOD_CC)|| adyenPaymentMethod.indexOf(PAYMENT_METHOD_ONECLICK) == 0) { + model.addAttribute(MODEL_CHECKOUT_SHOPPER_HOST, adyenCheckoutFacade.getCheckoutShopperHost()); + model.addAttribute(SHOPPER_LOCALE, adyenCheckoutFacade.getShopperLocale()); + model.addAttribute(MODEL_ORIGIN_KEY, adyenCheckoutFacade.getOriginKey()); + model.addAttribute(PAYMENT_DATA, paymentsResponse.getPaymentData()); + model.addAttribute(FINGERPRINT_TOKEN, paymentsResponse.getAuthentication().get(THREEDS2_FINGERPRINT_TOKEN)); + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.Validate3DS2PaymentPage; + } + } + if (CHALLENGESHOPPER == paymentsResponse.getResultCode()) { + if (adyenPaymentMethod.equals(PAYMENT_METHOD_CC)|| adyenPaymentMethod.indexOf(PAYMENT_METHOD_ONECLICK) == 0) { + model.addAttribute(MODEL_CHECKOUT_SHOPPER_HOST, adyenCheckoutFacade.getCheckoutShopperHost()); + model.addAttribute(SHOPPER_LOCALE, adyenCheckoutFacade.getShopperLocale()); + model.addAttribute(MODEL_ORIGIN_KEY, adyenCheckoutFacade.getOriginKey()); + model.addAttribute(PAYMENT_DATA, paymentsResponse.getPaymentData()); + model.addAttribute(CHALLENGE_TOKEN, paymentsResponse.getAuthentication().get(THREEDS2_CHALLENGE_TOKEN)); + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.Validate3DS2PaymentPage; + } + } } catch (Exception e) { LOGGER.error(ExceptionUtils.getStackTrace(e)); } @@ -208,6 +236,38 @@ else if (PAYMENT_METHOD_MULTIBANCO.equals(cartData.getAdyenPaymentMethod())) { return enterStep(model, redirectModel); } + @RequestMapping(value = "/3ds2-adyen-response", method = RequestMethod.POST) + @RequireHardLogIn + public String authorise3DS2Payment(final Model model, + final RedirectAttributes redirectModel, + final HttpServletRequest request) throws CMSItemNotFoundException, CommerceCartModificationException, UnknownHostException { + + String errorMessage = "checkout.error.authorization.failed"; + try { + OrderData orderData = adyenCheckoutFacade.handle3DS2Response(request); + LOGGER.debug("Redirecting to confirmation"); + return redirectToOrderConfirmationPage(orderData); + } catch (AdyenNonAuthorizedPaymentException e) { + PaymentsResponse paymentsResponse = e.getPaymentsResponse(); + if (paymentsResponse != null && paymentsResponse.getResultCode() == CHALLENGESHOPPER) { + model.addAttribute(MODEL_CHECKOUT_SHOPPER_HOST, adyenCheckoutFacade.getCheckoutShopperHost()); + model.addAttribute(SHOPPER_LOCALE, adyenCheckoutFacade.getShopperLocale()); + model.addAttribute(MODEL_ORIGIN_KEY, adyenCheckoutFacade.getOriginKey()); + model.addAttribute(PAYMENT_DATA, paymentsResponse.getPaymentData()); + model.addAttribute(CHALLENGE_TOKEN, paymentsResponse.getAuthentication().get("threeds2.challengeToken")); + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.Validate3DS2PaymentPage; + } + if (paymentsResponse != null && paymentsResponse.getResultCode() == PaymentsResponse.ResultCodeEnum.REFUSED) { + errorMessage = getErrorMessageByRefusalReason(paymentsResponse.getRefusalReason()); + } + } catch (Exception e) { + LOGGER.debug("Redirecting to summary" + errorMessage); + return redirectToSummaryWithError(redirectModel, errorMessage); + } + LOGGER.debug("Redirecting to final step of checkout" +errorMessage); + return redirectToSummaryWithError(redirectModel, errorMessage); + } + @RequestMapping(value = AUTHORISE_3D_SECURE_PAYMENT_URL, method = RequestMethod.POST) @RequireHardLogIn public String authorise3DSecurePayment(final Model model, diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base.properties b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base.properties index f0f72980d..7495c9274 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base.properties +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base.properties @@ -1,6 +1,6 @@ checkout.error.authorization.transaction.not.permitted=The transaction is not permitted. -checkout.error.authorization.cvc.declined=Declined due to the Card Security Code(CVC) being incorrect. Please check your CVC code! +checkout.error.authorization.cvc.declined=The payment is REFUSED. Please check your Card details. checkout.error.authorization.restricted.card=The card is restricted. checkout.error.authorization.payment.detail.not.found=The payment is REFUSED because the saved card is removed. Please try an other payment method. checkout.error.authorization.payment.refused=The payment is REFUSED. diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/securedFieldsMethod.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/securedFieldsMethod.tag index 299bc826e..034a91760 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/securedFieldsMethod.tag +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/securedFieldsMethod.tag @@ -35,15 +35,6 @@
- - - -
diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/3ds2_payment.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/3ds2_payment.jsp new file mode 100644 index 000000000..57b307413 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/3ds2_payment.jsp @@ -0,0 +1,97 @@ +<%@ page trimDirectiveWhitespaces="true" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + + +
+
+
+
+ + + + +
+
+
+ + \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/selectPaymentMethodPage.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/selectPaymentMethodPage.jsp index 3b9f325d6..1de2c6d57 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/selectPaymentMethodPage.jsp +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/selectPaymentMethodPage.jsp @@ -17,9 +17,9 @@ - + - +