Skip to content

Commit

Permalink
Merge pull request #269 from Adyen/develop
Browse files Browse the repository at this point in the history
Release 10.2.0
  • Loading branch information
saquibsayyad authored Oct 19, 2021
2 parents f10e9ca + 55924b8 commit c6bf887
Show file tree
Hide file tree
Showing 29 changed files with 118 additions and 334 deletions.
10 changes: 0 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,6 @@ Ratepay is supported via Adyen API.
### Pix
[Pix](https://docs.adyen.com/payment-methods/pix) is supported via Adyen component and API.

### Paypal Express Checkout Shortcut

Requires both Adyen API and HPP credentials.

The plugin offers:
- a facade (AdyenPaypalFacade) that takes care of the communication from and to Adyen regarding Paypal ECS
- a default controller that given a valid Cart, can initiate such payment "/en/adyen/paypal-ecs/initialize"

More details can be found here: https://docs.adyen.com/developers/payment-methods/paypal/express-checkout-shortcut

### Other alternative payment methods

Supported via Adyen Checkout.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static com.adyen.v6.constants.AdyenControllerConstants.COMPONENT_PREFIX;
import static com.adyen.v6.constants.AdyenControllerConstants.SUMMARY_CHECKOUT_PREFIX;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_AMAZONPAY;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BCMC_MOBILE;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_PIX;

@RestController
Expand All @@ -88,6 +91,10 @@ public class AdyenComponentController {
@Resource(name = "baseSiteService")
private BaseSiteService baseSiteService;

private final List<String> PAYMENT_METHODS_WITH_VALIDATED_TERMS = Arrays.asList(PAYMENT_METHOD_AMAZONPAY,
PAYMENT_METHOD_BCMC_MOBILE,
PAYMENT_METHOD_PIX);

@RequestMapping(value = "/payment", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String componentPayment(final HttpServletRequest request) throws AdyenComponentException {
Expand All @@ -112,9 +119,9 @@ public String componentPayment(final HttpServletRequest request) throws AdyenCom
paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), GooglePayDetails.class);
} else if(AmazonPayDetails.AMAZONPAY.equals(paymentMethod)) {
paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), AmazonPayDetails.class);
} else if(PAYMENT_METHOD_PIX.equals(paymentMethod)) {
} else if(PAYMENT_METHOD_PIX.equals(paymentMethod) || PAYMENT_METHOD_BCMC_MOBILE.equals(paymentMethod)) {
paymentMethodDetails = new DefaultPaymentMethodDetails();
paymentMethodDetails.setType(PAYMENT_METHOD_PIX);
paymentMethodDetails.setType(paymentMethod);
} else {
throw new InvalidCartException("checkout.error.paymentethod.formentry.invalid");
}
Expand Down Expand Up @@ -180,8 +187,8 @@ protected void validateOrderForm(JsonObject requestJson) throws InvalidCartExcep
JsonObject paymentMethodDetails = requestJson.get("paymentMethodDetails").getAsJsonObject();
String paymentMethod = gson.fromJson(paymentMethodDetails.get("type"), String.class);

// Pix and Amazon already have the terms validated on a previous step
if(!PAYMENT_METHOD_PIX.equals(paymentMethod) && !PAYMENT_METHOD_AMAZONPAY.equals(paymentMethod)
// Some methods already have the terms validated on a previous step
if (!PAYMENT_METHODS_WITH_VALIDATED_TERMS.contains(paymentMethod)
&& (termsCheck == null || !termsCheck)) {
throw new InvalidCartException("checkout.error.terms.not.accepted");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import static com.adyen.v6.constants.AdyenControllerConstants.SUMMARY_CHECKOUT_PREFIX;
import static com.adyen.v6.constants.Adyenv6coreConstants.AFTERPAY_TOUCH;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_APPLEPAY;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BCMC;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BOLETO;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_CC;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_MULTIBANCO;
Expand All @@ -102,7 +103,7 @@ public class AdyenSummaryCheckoutStepController extends AbstractCheckoutStepCont

private final static String SUMMARY = "summary";
private static final String AUTHORISE_3D_SECURE_PAYMENT_URL = "/authorise-3d-adyen-response";
private static final String HPP_RESULT_URL = "/hpp-adyen-response";
private static final String CHECKOUT_RESULT_URL = "/checkout-adyen-response";
private static final String REDIRECT_RESULT = "redirectResult";
private static final String ACTION = "action";

Expand Down Expand Up @@ -342,7 +343,7 @@ public String authorise3DSPayment(final RedirectAttributes redirectModel,
return REDIRECT_PREFIX + CART_PREFIX;
}

@RequestMapping(value = HPP_RESULT_URL, method = RequestMethod.GET)
@RequestMapping(value = CHECKOUT_RESULT_URL, method = RequestMethod.GET)
@RequireHardLogIn
public String handleAdyenResponse(final HttpServletRequest request, final RedirectAttributes redirectModel) {
String redirectResult = request.getParameter(REDIRECT_RESULT);
Expand Down Expand Up @@ -423,7 +424,7 @@ private void addMultibancoMessage(RedirectAttributes redirectModel, final String


private boolean is3DSPaymentMethod(String adyenPaymentMethod) {
return adyenPaymentMethod.equals(PAYMENT_METHOD_CC) || adyenPaymentMethod.indexOf(PAYMENT_METHOD_ONECLICK) == 0;
return adyenPaymentMethod.equals(PAYMENT_METHOD_CC) || adyenPaymentMethod.equals(PAYMENT_METHOD_BCMC) || adyenPaymentMethod.indexOf(PAYMENT_METHOD_ONECLICK) == 0;
}

private String redirectToSelectPaymentMethodWithError(final RedirectAttributes redirectModel, final String messageKey) {
Expand Down Expand Up @@ -455,7 +456,7 @@ private String getReturnUrl(String adyenPaymentMethod) {
if (is3DSPaymentMethod(adyenPaymentMethod)) {
url = SUMMARY_CHECKOUT_PREFIX + AUTHORISE_3D_SECURE_PAYMENT_URL;
} else {
url = SUMMARY_CHECKOUT_PREFIX + HPP_RESULT_URL;
url = SUMMARY_CHECKOUT_PREFIX + CHECKOUT_RESULT_URL;
}
BaseSiteModel currentBaseSite = baseSiteService.getCurrentBaseSite();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ payment.method.telephonenumber=Phone Number
checkout.summary.spinner.message=Please wait while your payment is processed. Do not click back or refresh the page.
checkout.summary.component.mbway.payment=Provide your MB WAY account data to finalize your payment
checkout.summary.component.notavailable=This payment method is not available on your current browser or device
checkout.summary.component.pix.generateqr = Generate QR Code
checkout.summary.component.generateqr = Generate QR Code
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ payment.method.telephonenumber=Phone Number
checkout.summary.spinner.message=Please wait while your payment is processed. Do not click back or refresh the page.
checkout.summary.component.mbway.payment=Provide your MB WAY account data to finalize your payment
checkout.summary.component.notavailable=This payment method is not available on your current browser or device
checkout.summary.component.pix.generateqr = Generate QR Code
checkout.summary.component.generateqr = Generate QR Code
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ payment.method.terminal.selector=Selecione o terminal
payment.method.telephonenumber=Número de telefone

checkout.summary.spinner.message=Aguarde...
checkout.summary.component.pix.generateqr = Gerar QR Code
checkout.summary.component.generateqr = Gerar QR Code
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@
<c:if test="${brandCode eq 'afterpay_default'}">
<div id="afterpay-container"></div>
</c:if>

<c:if test="${brandCode eq 'bcmc'}">
<div id="bcmc-container"></div>
</c:if>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
<spring:url value="/checkout/multi/adyen/summary/placeOrder" var="placeOrderUrl"/>
<spring:url value="/checkout/multi/termsAndConditions" var="getTermsAndConditionsUrl"/>

<c:set var="componentsWithPayButton" value="amazonpay,applepay,paypal,paywithgoogle,pix" />
<c:set var="componentsWithPayButton" value="[amazonpay],[applepay],[paypal],[paywithgoogle],[pix],[bcmc_mobile]" />
<c:set var="componentPaymentMethod" value="[${selectedPaymentMethod}]" />

<%-- Components --%>
<c:if test="${fn:contains(componentsWithPayButton, selectedPaymentMethod)}">
<c:if test="${fn:contains(componentsWithPayButton, componentPaymentMethod)}">
<div class="checkbox">
<label>
<input type="checkbox" id="terms-conditions-check-${label}" />
Expand All @@ -23,12 +24,12 @@
</div>

<c:choose>
<c:when test="${selectedPaymentMethod eq 'pix'}">
<%-- Render Pix QR code --%>
<c:when test="${componentPaymentMethod eq '[pix]' || componentPaymentMethod eq '[bcmc_mobile]'}">
<%-- Render QR code --%>
<button id="generateqr-${label}" type="submit" class="btn btn-primary btn-block">
<spring:theme code="checkout.summary.component.pix.generateqr" text="Generate QR Code" />
<spring:theme code="checkout.summary.component.generateqr" text="Generate QR Code" />
</button>
<div id="pix-container-${label}"></div>
<div id="qrcode-container-${label}"></div>
</c:when>
<c:otherwise>
<%-- Render payment button --%>
Expand All @@ -37,15 +38,15 @@
</c:choose>
</c:if>

<c:if test="${selectedPaymentMethod eq 'mbway'}">
<c:if test="${componentPaymentMethod eq '[mbway]'}">
<div class="chckt-pm__header js-chckt-pm__header">
<spring:theme code="checkout.summary.component.mbway.payment"/>
</div>
<div id="adyen-component-container-${label}"></div>
</c:if>

<%-- For components that do not have it's own button --%>
<c:if test="${not fn:contains(componentsWithPayButton, selectedPaymentMethod)}">
<c:if test="${not fn:contains(componentsWithPayButton, componentPaymentMethod)}">
<form:form action="${placeOrderUrl}" id="placeOrderForm-${label}" modelAttribute="placeOrderForm">
<div class="checkbox">
<label> <form:checkbox id="terms-conditions-check-${label}" path="termsCheck" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@
var amountJS = {value: "${amount.value}", currency: "${amount.currency}"};
AdyenCheckoutHybris.initiateAmazonPay(amountJS, ${deliveryAddress}, ${amazonPayConfiguration});
</c:when>
<c:when test="${selectedPaymentMethod eq 'bcmc_mobile'}">
AdyenCheckoutHybris.initiateBcmcMobile("hidden-xs");
AdyenCheckoutHybris.initiateBcmcMobile("visible-xs");
</c:when>
<%-- API only payments methods --%>
<c:otherwise>
AdyenCheckoutHybris.configureButton($( "#placeOrderForm-hidden-xs" ), true, "hidden-xs");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@
<c:if test="${paymentMethod.type eq 'afterpay_default'}">
AdyenCheckoutHybris.initiateAfterPay("${countryCode}");
</c:if>
<c:if test="${paymentMethod.type eq 'bcmc'}">
AdyenCheckoutHybris.initiateBcmc("${countryCode}");
</c:if>
</c:forEach>
<c:forEach items="${storedCards}" var="storedCard">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var AdyenCheckoutHybris = (function () {
selectedCardBrand: null,
sepaDirectDebit:null,
afterPay: null,
bcmc: null,

convertCardBrand: function () {
var cardBrand = this.selectedCardBrand;
Expand Down Expand Up @@ -148,6 +149,24 @@ var AdyenCheckoutHybris = (function () {
if (paymentMethod === "giftcard") {
$( 'input[name="giftCardBrand"]' ).val($( 'input[type=radio][name=paymentMethod]:checked' ).attr('brand'));
}

if (paymentMethod === "bcmc") {
if (!this.bcmc.state.isValid) {
window.alert("Please fill all the details");
this.bcmc.showValidation();
document.getElementById("bcmc-container").scrollIntoView();
return false;
}
var state = this.bcmc.data.paymentMethod;
$( 'input[name="encryptedCardNumber"]' ).val( state.encryptedCardNumber );
$( 'input[name="encryptedExpiryMonth"]' ).val( state.encryptedExpiryMonth );
$( 'input[name="encryptedExpiryYear"]' ).val( state.encryptedExpiryYear );
$( 'input[name="cardHolder"]' ).val( state.holderName );
$( 'input[name="cardBrand"]' ).val( 'bcmc' );
$( 'input[name="cardType"]' ).val( 'debit' );
$( 'input[name="browserInfo"]' ).val( JSON.stringify( this.bcmc.data.browserInfo ) );
}

return true;
},

Expand Down Expand Up @@ -612,7 +631,7 @@ var AdyenCheckoutHybris = (function () {
AdyenCheckoutHybris.hideSpinner();
AdyenCheckoutHybris.submitDetails(state.data, AdyenCheckoutHybris.handleResult);
}
}).mount('#pix-container-' + label);
}).mount('#qrcode-container-' + label);
AdyenCheckoutHybris.hideSpinner();
}
};
Expand All @@ -621,6 +640,43 @@ var AdyenCheckoutHybris = (function () {
});
},

initiateBcmc: function () {
this.bcmc = this.checkout.create("bcmc", {
hasHolderName: true,
holderNameRequired: true
});

try {
this.bcmc.mount('#bcmc-container');
} catch (e) {
console.log('Something went wrong trying to mount the BCMC component: ' + e);
}
},

initiateBcmcMobile: function (label) {
$("#generateqr-" + label).click(function () {
AdyenCheckoutHybris.showSpinner();
if (!AdyenCheckoutHybris.isTermsAccepted(label)) {
AdyenCheckoutHybris.handleResult(ErrorMessages.TermsNotAccepted, true)
} else {
$("#generateqr-" + label).hide();
$(".checkbox").hide();
var actionHandler = {
handleAction : function (action) {
AdyenCheckoutHybris.checkout.createFromAction(action, {
onAdditionalDetails : function(state) {
AdyenCheckoutHybris.hideSpinner();
AdyenCheckoutHybris.submitDetails(state.data, AdyenCheckoutHybris.handleResult);
}
}).mount('#qrcode-container-' + label);
AdyenCheckoutHybris.hideSpinner();
}
};
AdyenCheckoutHybris.makePayment({ type: "bcmc_mobile" }, actionHandler, AdyenCheckoutHybris.handleResult, label);
}
});
},

configureButton: function (form, useSpinner, label) {
$(document).ready(function () {
$("#placeOrder-" + label).click(function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ module.name=platform-module
name=adyenv6b2ccheckoutaddon
releasedate=20170509 1903
vendor=adyen
version=10.1.0
version.api=10.1.0
version=10.2.0
version.api=10.2.0
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.adyen.model.checkout.CheckoutPaymentsAction;
import com.adyen.model.checkout.PaymentsDetailsResponse;
import com.adyen.model.checkout.PaymentsResponse;
import com.adyen.util.HMACValidator;
import com.adyen.v6.converters.PaymentsResponseConverter;
import com.adyen.v6.exceptions.AdyenNonAuthorizedPaymentException;
import com.adyen.v6.factory.AdyenPaymentServiceFactory;
Expand Down Expand Up @@ -63,16 +62,11 @@

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Collections;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import static com.adyen.constants.ApiConstants.Redirect.Data.MD;
import static com.adyen.constants.HPPConstants.Fields.CURRENCY_CODE;
import static com.adyen.constants.HPPConstants.Fields.PAYMENT_AMOUNT;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_CC;
import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_ONECLICK;
import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.SESSION_LOCKED_CART;
Expand Down Expand Up @@ -120,9 +114,6 @@ public class AdyenCheckoutFacadeTest {
@Mock
private CheckoutCustomerStrategy checkoutCustomerStrategyMock;

@Mock
private HMACValidator hmacValidatorMock;

@Mock
private AdyenPaymentServiceFactory adyenPaymentServiceFactoryMock;

Expand Down Expand Up @@ -153,14 +144,9 @@ public void setUp() throws SignatureException, InvalidCartException {
paymentsDetailsResponseMock = mock(PaymentsDetailsResponse.class);
CartData cartDataMock = mock(CartData.class);

when(baseStoreModelMock.getAdyenSkinHMAC()).thenReturn("hmacKey");
when(baseStoreModelMock.getAdyenMerchantAccount()).thenReturn("merchantAccount");
when(baseStoreModelMock.getAdyenSkinCode()).thenReturn("skinCode");
when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock);

when(hmacValidatorMock.calculateHMAC(isA(String.class), isA(String.class))).thenReturn("merchantSig");
when(hmacValidatorMock.getDataToSign(isA(SortedMap.class))).thenReturn("dataToSign");

when(cartModelMock.getCode()).thenReturn("code");
when(cartServiceMock.getSessionCart()).thenReturn(cartModelMock);

Expand Down Expand Up @@ -217,20 +203,6 @@ public void testLockSessionCart() {
verify(sessionServiceMock).removeAttribute(SESSION_CART_PARAMETER_NAME);
}

@Test
public void testValidateHPPResponse() throws NoSuchAlgorithmException, SignatureException {
SortedMap<String, String> hppResponseData = new TreeMap<>();

adyenCheckoutFacade.validateHPPResponse(hppResponseData, "merchantSig");

try {
adyenCheckoutFacade.validateHPPResponse(hppResponseData, "wrongMerchantSig");

fail("Expected exception!");
} catch (SignatureException ignored) {
}
}

@Test
public void testAuthorizeCardPayment() throws Exception {
HttpServletRequest requestMock = mock(HttpServletRequest.class);
Expand Down Expand Up @@ -319,16 +291,6 @@ public void testHandle3DResponse() throws Exception {
}
}

@Test
public void testInitializeHostedPayment() throws SignatureException, InvalidCartException {
CartData cartData = createCartData();

Map<String, String> hppFormData = adyenCheckoutFacade.initializeHostedPayment(cartData, "redirectUrl");

assertEquals("1234", hppFormData.get(PAYMENT_AMOUNT));
assertEquals("EUR", hppFormData.get(CURRENCY_CODE));
}

private CartData createCartData() {
CartData cartData = new CartData();

Expand Down
Loading

0 comments on commit c6bf887

Please sign in to comment.