Skip to content

Commit

Permalink
Merge pull request #349 from Adyen/feature/AD-195
Browse files Browse the repository at this point in the history
[AD-195] Giftcard / Givex support on frontend + BLIK
  • Loading branch information
kpieloch authored Feb 20, 2024
2 parents 4c36b07 + 7e803a7 commit b0df906
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 201 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
Expand Down Expand Up @@ -124,146 +123,150 @@ public String componentPayment(final HttpServletRequest request) throws AdyenCom
} else if (PAYMENT_METHOD_PIX.equals(paymentMethod) || PAYMENT_METHOD_BCMC_MOBILE.equals(paymentMethod)) {
paymentMethodDetails = new CardDetails();
paymentMethodDetails.setType(paymentMethod);
} else {
throw new InvalidCartException("checkout.error.paymentethod.formentry.invalid");
}

cartData.setAdyenReturnUrl(getReturnUrl(paymentMethod));

PaymentsResponse paymentsResponse = getAdyenCheckoutFacade().componentPayment(request, cartData, paymentMethodDetails);
return gson.toJson(paymentsResponse);
} catch(InvalidCartException e){
LOGGER.error("InvalidCartException: " + e.getMessage());
throw new AdyenComponentException(e.getMessage());
}
catch(ApiException e){
LOGGER.error("ApiException: " + e.toString());
throw new AdyenComponentException("checkout.error.authorization.payment.refused");
} catch(AdyenNonAuthorizedPaymentException e){
LOGGER.warn("AdyenNonAuthorizedPaymentException occurred. Payment " + e.getPaymentResult().getPspReference() + "is refused.");
throw new AdyenComponentException("checkout.error.authorization.payment.refused");
} catch(Exception e){
LOGGER.error("Exception", e);
throw new AdyenComponentException("checkout.error.authorization.payment.error");
} else if (BlikDetails.BLIK.equals(paymentMethod)) {
paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), BlikDetails.class);
} else if (CardDetails.GIFTCARD.equals(paymentMethod)) {
paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), CardDetails.class);
paymentMethodDetails.setType(paymentMethod);
} else {
throw new InvalidCartException("checkout.error.paymentethod.formentry.invalid");
}
}

@RequestMapping(value = "/submit-details", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String submitDetails ( final HttpServletRequest request) throws AdyenComponentException {
try {
String requestJsonString = IOUtils.toString(request.getInputStream(), String.valueOf(StandardCharsets.UTF_8));
JsonObject requestJson = new JsonParser().parse(requestJsonString).getAsJsonObject();

Gson gson = new GsonBuilder().disableHtmlEscaping().create();
Type mapType = new TypeToken<Map<String, String>>() {
}.getType();
Map<String, String> details = gson.fromJson(requestJson.get("details"), mapType);
String paymentData = gson.fromJson(requestJson.get("paymentData"), String.class);

PaymentsDetailsResponse paymentsResponse = getAdyenCheckoutFacade().componentDetails(request, details, paymentData);
return gson.toJson(paymentsResponse);
} catch (ApiException e) {
LOGGER.error("ApiException: " + e.toString());
throw new AdyenComponentException("checkout.error.authorization.payment.refused");
} catch (Exception e) {
LOGGER.error("Exception", e);
throw new AdyenComponentException("checkout.error.authorization.payment.error");
}
cartData.setAdyenReturnUrl(getReturnUrl(paymentMethod));

PaymentsResponse paymentsResponse = getAdyenCheckoutFacade().componentPayment(request, cartData, paymentMethodDetails);
return gson.toJson(paymentsResponse);
} catch (InvalidCartException e) {
LOGGER.error("InvalidCartException: " + e.getMessage());
throw new AdyenComponentException(e.getMessage());
} catch (ApiException e) {
LOGGER.error("ApiException: " + e.toString());
throw new AdyenComponentException("checkout.error.authorization.payment.refused");
} catch (AdyenNonAuthorizedPaymentException e) {
LOGGER.warn("AdyenNonAuthorizedPaymentException occurred. Payment " + e.getPaymentResult().getPspReference() + "is refused.");
throw new AdyenComponentException("checkout.error.authorization.payment.refused");
} catch (Exception e) {
LOGGER.error("Exception", e);
throw new AdyenComponentException("checkout.error.authorization.payment.error");
}
}

@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = AdyenComponentException.class)
public String adyenComponentExceptionHandler (AdyenComponentException e){
return e.getMessage();
}
@RequestMapping(value = "/submit-details", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String submitDetails(final HttpServletRequest request) throws AdyenComponentException {
try {
String requestJsonString = IOUtils.toString(request.getInputStream(), String.valueOf(StandardCharsets.UTF_8));
JsonObject requestJson = new JsonParser().parse(requestJsonString).getAsJsonObject();

/**
* Validates the order form before to filter out invalid order states
*
* @return True if the order form is invalid and false if everything is valid.
* @param requestJson
*/
protected void validateOrderForm (JsonObject requestJson) throws InvalidCartException {
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
Boolean termsCheck = gson.fromJson(requestJson.get("termsCheck"), Boolean.class);
JsonObject paymentMethodDetails = requestJson.get("paymentMethodDetails").getAsJsonObject();
String paymentMethod = gson.fromJson(paymentMethodDetails.get("type"), String.class);

// 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");
}

if (getCheckoutFlowFacade().hasNoDeliveryAddress()) {
throw new InvalidCartException("checkout.deliveryAddress.notSelected");
}

if (getCheckoutFlowFacade().hasNoDeliveryMode()) {
throw new InvalidCartException("checkout.deliveryMethod.notSelected");
}

if (getCheckoutFlowFacade().hasNoPaymentInfo()) {
throw new InvalidCartException("checkout.paymentMethod.notSelected");
}

final CartData cartData = getCheckoutFacade().getCheckoutCart();
Type mapType = new TypeToken<Map<String, String>>() {
}.getType();
Map<String, String> details = gson.fromJson(requestJson.get("details"), mapType);
String paymentData = gson.fromJson(requestJson.get("paymentData"), String.class);

PaymentsDetailsResponse paymentsResponse = getAdyenCheckoutFacade().componentDetails(request, details, paymentData);
return gson.toJson(paymentsResponse);
} catch (ApiException e) {
LOGGER.error("ApiException: " + e.toString());
throw new AdyenComponentException("checkout.error.authorization.payment.refused");
} catch (Exception e) {
LOGGER.error("Exception", e);
throw new AdyenComponentException("checkout.error.authorization.payment.error");
}
}

if (!getCheckoutFacade().containsTaxValues()) {
LOGGER.error(String.format("Cart %s does not have any tax values, which means the tax cacluation was not properly done, placement of order can't continue", cartData.getCode()));
throw new InvalidCartException("checkout.error.tax.missing");
}
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = AdyenComponentException.class)
public String adyenComponentExceptionHandler(AdyenComponentException e) {
return e.getMessage();
}

if (!cartData.isCalculated()) {
LOGGER.error(String.format("Cart %s has a calculated flag of FALSE, placement of order can't continue", cartData.getCode()));
throw new InvalidCartException("checkout.error.cart.notcalculated");
}
/**
* Validates the order form before to filter out invalid order states
*
* @param requestJson
* @return True if the order form is invalid and false if everything is valid.
*/
protected void validateOrderForm(JsonObject requestJson) throws InvalidCartException {
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
Boolean termsCheck = gson.fromJson(requestJson.get("termsCheck"), Boolean.class);
JsonObject paymentMethodDetails = requestJson.get("paymentMethodDetails").getAsJsonObject();
String paymentMethod = gson.fromJson(paymentMethodDetails.get("type"), String.class);

// 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");
}

private String getReturnUrl (String paymentMethod){
String url;
if (GooglePayDetails.GOOGLEPAY.equals(paymentMethod)) {
//Google Pay will only use returnUrl if redirected to 3DS authentication
url = SUMMARY_CHECKOUT_PREFIX + "/authorise-3d-adyen-response";
} else {
url = COMPONENT_PREFIX + "/submit-details";
}
BaseSiteModel currentBaseSite = baseSiteService.getCurrentBaseSite();
return siteBaseUrlResolutionService.getWebsiteUrlForSite(currentBaseSite, true, url);
if (getCheckoutFlowFacade().hasNoDeliveryAddress()) {
throw new InvalidCartException("checkout.deliveryAddress.notSelected");
}

public AdyenCheckoutFacade getAdyenCheckoutFacade () {
return adyenCheckoutFacade;
if (getCheckoutFlowFacade().hasNoDeliveryMode()) {
throw new InvalidCartException("checkout.deliveryMethod.notSelected");
}

public void setAdyenCheckoutFacade (AdyenCheckoutFacade adyenCheckoutFacade){
this.adyenCheckoutFacade = adyenCheckoutFacade;
if (getCheckoutFlowFacade().hasNoPaymentInfo()) {
throw new InvalidCartException("checkout.paymentMethod.notSelected");
}

public CheckoutFlowFacade getCheckoutFlowFacade () {
return checkoutFlowFacade;
}
final CartData cartData = getCheckoutFacade().getCheckoutCart();

public void setCheckoutFlowFacade (CheckoutFlowFacade checkoutFlowFacade){
this.checkoutFlowFacade = checkoutFlowFacade;
if (!getCheckoutFacade().containsTaxValues()) {
LOGGER.error(String.format("Cart %s does not have any tax values, which means the tax cacluation was not properly done, placement of order can't continue", cartData.getCode()));
throw new InvalidCartException("checkout.error.tax.missing");
}

public AcceleratorCheckoutFacade getCheckoutFacade () {
return checkoutFacade;
if (!cartData.isCalculated()) {
LOGGER.error(String.format("Cart %s has a calculated flag of FALSE, placement of order can't continue", cartData.getCode()));
throw new InvalidCartException("checkout.error.cart.notcalculated");
}
}

public void setCheckoutFacade (AcceleratorCheckoutFacade checkoutFacade){
this.checkoutFacade = checkoutFacade;
private String getReturnUrl(String paymentMethod) {
String url;
if (GooglePayDetails.GOOGLEPAY.equals(paymentMethod)) {
//Google Pay will only use returnUrl if redirected to 3DS authentication
url = SUMMARY_CHECKOUT_PREFIX + "/authorise-3d-adyen-response";
} else {
url = COMPONENT_PREFIX + "/submit-details";
}
BaseSiteModel currentBaseSite = baseSiteService.getCurrentBaseSite();
return siteBaseUrlResolutionService.getWebsiteUrlForSite(currentBaseSite, true, url);
}

private boolean isValidateSessionCart () {
CartData cart = getCheckoutFacade().getCheckoutCart();
final AddressData deliveryAddress = cart.getDeliveryAddress();
if (deliveryAddress == null || deliveryAddress.getCountry() == null || deliveryAddress.getCountry().getIsocode() == null) {
return false;
}
return true;
public AdyenCheckoutFacade getAdyenCheckoutFacade() {
return adyenCheckoutFacade;
}

public void setAdyenCheckoutFacade(AdyenCheckoutFacade adyenCheckoutFacade) {
this.adyenCheckoutFacade = adyenCheckoutFacade;
}

public CheckoutFlowFacade getCheckoutFlowFacade() {
return checkoutFlowFacade;
}

public void setCheckoutFlowFacade(CheckoutFlowFacade checkoutFlowFacade) {
this.checkoutFlowFacade = checkoutFlowFacade;
}

public AcceleratorCheckoutFacade getCheckoutFacade() {
return checkoutFacade;
}

public void setCheckoutFacade(AcceleratorCheckoutFacade checkoutFacade) {
this.checkoutFacade = checkoutFacade;
}

private boolean isValidateSessionCart() {
CartData cart = getCheckoutFacade().getCheckoutCart();
final AddressData deliveryAddress = cart.getDeliveryAddress();
if (deliveryAddress == null || deliveryAddress.getCountry() == null || deliveryAddress.getCountry().getIsocode() == null) {
return false;
}
return true;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ payment.method.label.information=Bank Card

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.blik.payment=Provide your BLIK code to finalize your payment
checkout.summary.component.giftcard.payment=Provide your Giftcard data to finalize your payment
checkout.summary.component.notavailable=This payment method is not available on your current browser or device
checkout.summary.component.generateqr = Generate QR Code
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ 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.blik.payment=Provide your BLIK code to finalize your payment
checkout.summary.component.giftcard.payment=Provide your Giftcard data to finalize your payment
checkout.summary.component.notavailable=This payment method is not available on your current browser or device
checkout.summary.component.generateqr = Generate QR Code

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@
<div id="adyen-component-container-${label}"></div>
</c:if>

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

<c:if test="${componentPaymentMethod eq '[giftcard]'}">
<div class="chckt-pm__header js-chckt-pm__header">
<spring:theme code="checkout.summary.component.giftcard.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, componentPaymentMethod)}">
<form:form action="${placeOrderUrl}" id="placeOrderForm-${label}" modelAttribute="placeOrderForm">
Expand Down
Loading

0 comments on commit b0df906

Please sign in to comment.