Skip to content

Commit

Permalink
implement paypal payment option #77
Browse files Browse the repository at this point in the history
  • Loading branch information
syjer committed Jul 13, 2016
1 parent 9930d24 commit f824021
Show file tree
Hide file tree
Showing 25 changed files with 442 additions and 40 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ dependencies {
compile "org.apache.logging.log4j:log4j-jcl:$log4jVersion"
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion"
compile "com.stripe:stripe-java:$stripeVersion"
compile 'com.paypal.sdk:rest-api-sdk:1.8.0'
compile "com.google.maps:google-maps-services:0.1.7"
compile "org.apache.commons:commons-lang3:3.4"
compile "com.squareup.okhttp:okhttp:2.4.0"
Expand Down
53 changes: 45 additions & 8 deletions src/main/java/alfio/controller/ReservationController.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@
import alfio.controller.form.UpdateTicketOwnerForm;
import alfio.controller.support.SessionUtil;
import alfio.controller.support.TicketDecorator;
import alfio.manager.EventManager;
import alfio.manager.NotificationManager;
import alfio.manager.StripeManager;
import alfio.manager.TicketReservationManager;
import alfio.manager.*;
import alfio.manager.support.OrderSummary;
import alfio.manager.support.PaymentResult;
import alfio.manager.system.ConfigurationManager;
Expand All @@ -40,6 +37,7 @@
import alfio.util.TemplateManager;
import alfio.util.TemplateManager.TemplateOutput;
import alfio.util.ValidationResult;
import com.paypal.base.rest.PayPalRESTException;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -74,6 +72,7 @@ public class ReservationController {
private final OrganizationRepository organizationRepository;

private final StripeManager stripeManager;
private final PaypalManager paypalManager;
private final TemplateManager templateManager;
private final MessageSource messageSource;
private final ConfigurationManager configurationManager;
Expand All @@ -92,7 +91,8 @@ public ReservationController(EventRepository eventRepository,
ConfigurationManager configurationManager,
NotificationManager notificationManager,
TicketHelper ticketHelper,
TicketFieldRepository ticketFieldRepository) {
TicketFieldRepository ticketFieldRepository,
PaypalManager paypalManager) {
this.eventRepository = eventRepository;
this.eventManager = eventManager;
this.ticketReservationManager = ticketReservationManager;
Expand All @@ -104,22 +104,44 @@ public ReservationController(EventRepository eventRepository,
this.notificationManager = notificationManager;
this.ticketHelper = ticketHelper;
this.ticketFieldRepository = ticketFieldRepository;
this.paypalManager = paypalManager;
}

@RequestMapping(value = "/event/{eventName}/reservation/{reservationId}/book", method = RequestMethod.GET)
public String showPaymentPage(@PathVariable("eventName") String eventName,
@PathVariable("reservationId") String reservationId,
//paypal related parameters
@RequestParam(value = "paymentId", required = false) String paypalPaymentId,
@RequestParam(value = "PayerID", required = false) String paypalPayerID,
@RequestParam(value = "paypal-success", required = false) Boolean isPaypalSuccess,
@RequestParam(value = "paypal-error", required = false) Boolean isPaypalError,
@RequestParam(value = "fullName", required = false) String fullName,
@RequestParam(value = "email", required = false) String email,
@RequestParam(value = "billingAddress", required = false) String billingAddress,
@RequestParam(value = "hmac", required = false) String hmac,
Model model,
Locale locale) {

return eventRepository.findOptionalByShortName(eventName)
.map(event -> ticketReservationManager.findById(reservationId)
.map(reservation -> {

if(reservation.getStatus() != TicketReservationStatus.PENDING) {
if (reservation.getStatus() != TicketReservationStatus.PENDING) {
return redirectReservation(Optional.of(reservation), eventName, reservationId);
}

if (Boolean.TRUE.equals(isPaypalSuccess) && paypalPayerID != null && paypalPaymentId != null) {
model.addAttribute("paypalPaymentId", paypalPaymentId)
.addAttribute("paypalPayerID", paypalPayerID)
.addAttribute("paypalCheckoutConfirmation", true)
.addAttribute("fullName", fullName)
.addAttribute("email", email)
.addAttribute("billingAddress", billingAddress)
.addAttribute("hmac", hmac);
} else {
model.addAttribute("paypalCheckoutConfirmation", false);
}

OrderSummary orderSummary = ticketReservationManager.orderSummaryForReservationId(reservationId, event, locale);
model.addAttribute("orderSummary", orderSummary);
model.addAttribute("reservationId", reservationId);
Expand Down Expand Up @@ -335,13 +357,28 @@ public String handleReservation(@PathVariable("eventName") String eventName,
bindingResult.reject(ErrorsCode.STEP_2_ORDER_EXPIRED);
}
final TicketReservationManager.TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId);
paymentForm.validate(bindingResult, reservationCost, event.getAllowedPaymentProxies());
paymentForm.validate(bindingResult, reservationCost, event);
if (bindingResult.hasErrors()) {
SessionUtil.addToFlash(bindingResult, redirectAttributes);
return redirectReservation(ticketReservation, eventName, reservationId);
}

//handle paypal redirect!
if(paymentForm.getPaymentMethod() == PaymentProxy.PAYPAL && !paymentForm.hasPaypalTokens()) {
OrderSummary orderSummary = ticketReservationManager.orderSummaryForReservationId(reservationId, event, locale);
try {
String checkoutUrl = paypalManager.createCheckoutRequest(event, reservationId, orderSummary, paymentForm.getFullName(), paymentForm.getEmail(), paymentForm.getBillingAddress(), locale);
return "redirect:" + checkoutUrl;
} catch (Exception e) {
bindingResult.reject(ErrorsCode.STEP_2_PAYMENT_REQUEST_CREATION);
return redirectReservation(ticketReservation, eventName, reservationId);
}
}
//


boolean directTicketAssignment = Optional.ofNullable(paymentForm.getExpressCheckoutRequested()).map(b -> Boolean.logicalAnd(b, isExpressCheckoutEnabled(event, ticketReservationManager.orderSummaryForReservationId(reservationId, event, locale)))).orElse(false);
final PaymentResult status = ticketReservationManager.confirm(paymentForm.getStripeToken(), event, reservationId, paymentForm.getEmail(),
final PaymentResult status = ticketReservationManager.confirm(paymentForm.getToken(), paymentForm.getPaypalPayerID(), event, reservationId, paymentForm.getEmail(),
paymentForm.getFullName(), locale, paymentForm.getBillingAddress(), reservationCost, SessionUtil.retrieveSpecialPriceSessionId(request),
Optional.ofNullable(paymentForm.getPaymentMethod()), directTicketAssignment);

Expand Down
27 changes: 26 additions & 1 deletion src/main/java/alfio/controller/form/PaymentForm.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
*/
package alfio.controller.form;

import alfio.manager.PaypalManager;
import alfio.manager.TicketReservationManager;
import alfio.model.Event;
import alfio.model.transaction.PaymentProxy;
import alfio.util.ErrorsCode;
import lombok.Data;
Expand All @@ -33,9 +35,12 @@
@Data
public class PaymentForm {
private String stripeToken;
private String paypalPaymentId;
private String paypalPayerID;
private String email;
private String fullName;
private String billingAddress;
private String hmac;
private Boolean cancelReservation;
private Boolean termAndConditionsAccepted;
private PaymentProxy paymentMethod;
Expand All @@ -48,7 +53,23 @@ private static void rejectIfOverLength(BindingResult bindingResult, String field
}
}

public void validate(BindingResult bindingResult, TicketReservationManager.TotalPrice reservationCost, List<PaymentProxy> allowedPaymentMethods) {
public String getToken() {
if(paymentMethod == PaymentProxy.STRIPE) {
return stripeToken;
} else if(paymentMethod == PaymentProxy.PAYPAL) {
return paypalPaymentId;
} else {
return null;
}
}

public boolean hasPaypalTokens() {
return StringUtils.isNotBlank(paypalPayerID) && StringUtils.isNotBlank(paypalPaymentId);
}

public void validate(BindingResult bindingResult, TicketReservationManager.TotalPrice reservationCost, Event event) {

List<PaymentProxy> allowedPaymentMethods = event.getAllowedPaymentProxies();

Optional<PaymentProxy> paymentProxyOptional = Optional.ofNullable(paymentMethod);
PaymentProxy paymentProxy = paymentProxyOptional.filter(allowedPaymentMethods::contains).orElse(PaymentProxy.STRIPE);
Expand Down Expand Up @@ -80,6 +101,10 @@ public void validate(BindingResult bindingResult, TicketReservationManager.Total
if (email != null && !email.contains("@") && !bindingResult.hasFieldErrors("email")) {
bindingResult.rejectValue("email", ErrorsCode.STEP_2_INVALID_EMAIL);
}

if (hasPaypalTokens() && !PaypalManager.isValidHMAC(fullName, email, billingAddress, hmac, event)) {
bindingResult.reject(ErrorsCode.STEP_2_INVALID_HMAC);
}
}

public Boolean shouldCancelReservation() {
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/alfio/manager/PaymentManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import alfio.model.Event;
import alfio.model.transaction.PaymentProxy;
import alfio.repository.TransactionRepository;
import alfio.util.ErrorsCode;
import com.paypal.base.rest.PayPalRESTException;
import com.stripe.exception.StripeException;
import com.stripe.model.Charge;
import lombok.extern.log4j.Log4j2;
Expand All @@ -34,12 +36,15 @@
public class PaymentManager {

private final StripeManager stripeManager;
private final PaypalManager paypalManager;
private final TransactionRepository transactionRepository;

@Autowired
public PaymentManager(StripeManager stripeManager,
PaypalManager paypalManager,
TransactionRepository transactionRepository) {
this.stripeManager = stripeManager;
this.paypalManager = paypalManager;
this.transactionRepository = transactionRepository;
}

Expand Down Expand Up @@ -87,4 +92,18 @@ public PaymentResult processOfflinePayment(String reservationId, int price, Even
return PaymentResult.successful(transactionId);
}

public PaymentResult processPaypalPayment(String reservationId, String token, String payerId, int price, Event event) {
try {
String transactionId = paypalManager.commitPayment(reservationId, token, payerId, event);
transactionRepository.insert(transactionId, reservationId,
ZonedDateTime.now(), price, event.getCurrency(), "Paypal confirmation", PaymentProxy.PAYPAL.name());
return PaymentResult.successful(transactionId);
} catch (Exception e) {
log.warn("errow while processing paypal payment: " + e.getMessage(), e);
if(e instanceof PayPalRESTException) {
return PaymentResult.unsuccessful(ErrorsCode.STEP_2_PAYPAL_UNEXPECTED);
}
throw new IllegalStateException(e);
}
}
}
Loading

0 comments on commit f824021

Please sign in to comment.