package controllers;
import com.google.common.primitives.Ints;
import controllers.actions.FormHandler;
import controllers.actions.CartNotEmpty;
import de.paymill.Paymill;
import de.paymill.PaymillException;
import de.paymill.model.Payment;
import de.paymill.model.Transaction;
import de.paymill.net.ApiException;
import de.paymill.service.PaymentService;
import de.paymill.service.TransactionService;
import forms.addressForm.ListAddress;
import forms.addressForm.SetAddress;
import forms.checkoutForm.DoCheckout;
import forms.checkoutForm.SetShippingMethod;
import io.sphere.client.model.Money;
import io.sphere.client.shop.CreateOrderBuilder;
import io.sphere.client.shop.model.*;
import play.Play;
import play.data.Form;
import play.mvc.Content;
import play.mvc.Result;
import play.mvc.With;
import sphere.ShopController;
import views.html.checkouts;
import views.html.orders;
import static play.data.Form.form;
import static utils.ControllerHelper.*;
import static utils.ViewHelper.getCurrentCart;
import static utils.ViewHelper.getPrice;
public class Checkouts extends ShopController {
final static String paymillKey = Play.application().configuration().getString("paymill.key.private", "");
final static Form<SetAddress> setAddressForm = form(SetAddress.class);
final static Form<SetShippingMethod> setShippingForm = form(SetShippingMethod.class);
final static Form<DoCheckout> doCheckoutForm = form(DoCheckout.class);
public static Result getShippingAddress() {
return ok(ListAddress.getJson(getCurrentCart().getShippingAddress()));
}
public static Result getShippingMethod() {
return ok(SetShippingMethod.getJson(getShippingMethods()));
}
@With(CartNotEmpty.class)
public static Result show() {
return ok(showPage(1));
}
@With(CartNotEmpty.class)
public static Result showShippingAddress() {
return ok(showPage(2));
}
@With(CartNotEmpty.class)
public static Result showShippingMethod() {
return ok(showPage(3));
}
@With(CartNotEmpty.class)
public static Result showPaymentMethod() {
return ok(showPage(4));
}
@With(FormHandler.class)
public static Result setShippingAddress() {
// Case missing or invalid form data
Form<SetAddress> form = setAddressForm.bindFromRequest();
if (form.hasErrors()) {
displayErrors("set-address", form);
return badRequest(showPage(2, form, null));
}
// Case valid shipping address
SetAddress setAddress = form.get();
if (setAddress.email != null) {
setCurrentCart(sphere().currentCart().setCustomerEmail(setAddress.email));
}
setCurrentCart(sphere().currentCart().setShippingAddress(setAddress.getAddress()));
setAddress.displaySuccessMessage();
return ok(showPage(3));
}
@With(FormHandler.class)
public static Result setShippingMethod() {
// Case missing or invalid form data
Form<SetShippingMethod> form = setShippingForm.bindFromRequest();
if (form.hasErrors()) {
displayErrors("set-shipping", form);
return badRequest(showPage(3, null, form));
}
// Case valid shipping method
SetShippingMethod setShipping = form.get();
setCurrentCart(sphere().currentCart().setShippingMethod(setShipping.getShippingMethod()));
setShipping.displaySuccessMessage();
return ok(showPage(4));
}
public static Result submit() {
// Case missing or invalid form data
Form<DoCheckout> form = doCheckoutForm.bindFromRequest();
if (form.hasErrors()) {
displayErrors("", form);
return badRequest(showPage(4));
}
// Case cart changed
DoCheckout doCheckout = form.get();
if (!sphere().currentCart().isSafeToCreateOrder(doCheckout.cartSnapshot)) {
doCheckout.displayCartChangedError();
redirect(controllers.routes.Checkouts.show());
}
// Case payment failure
try {
// Get payment object from token
Paymill.setApiKey(paymillKey);
PaymentService paymentSrv = Paymill.getService(PaymentService.class);
Payment payment = paymentSrv.create(doCheckout.paymillToken);
// Set transaction details
TransactionService transactionSrv = Paymill.getService(TransactionService.class);
Transaction transaction = new Transaction();
Money money = getPrice(getCurrentCart());
transaction.setPayment(payment);
transaction.setAmount(Ints.checkedCast(money.getCentAmount()));
transaction.setCurrency(money.getCurrencyCode());
// Execute charge transaction
play.Logger.debug("Cart " + doCheckout.cartSnapshot + " - Executing payment " + payment.getId()
+ " of " + transaction.getAmount() + " (cents) " + transaction.getCurrency()
+ " with token " + doCheckout.paymillToken);
transactionSrv.create(transaction);
} catch (PaymillException pe) {
play.Logger.error(pe.getMessage());
flash("error", "Payment failed unexpectedly, please try again");
return internalServerError(showPage(4));
}
// Case success purchase
String orderNumber = "O-" + System.currentTimeMillis();
CreateOrderBuilder builder = new CreateOrderBuilder(getCurrentCart().getIdAndVersion(), PaymentState.Paid)
.setCartSnapshotId(doCheckout.cartSnapshot)
.setOrderNumber(orderNumber);
Order order = sphere().currentCart().createOrder(builder);
play.Logger.debug("Cart " + doCheckout.cartSnapshot + " - Order created");
flash("success", "Congratulations, you finished your order!");
return ok(orders.render(order));
}
protected static Content showPage(int page) {
return showPage(page, null, null);
}
protected static Content showPage(int page, Form<SetAddress> addressForm, Form<SetShippingMethod> shippingForm) {
Cart cart = getCurrentCart();
if (addressForm == null) {
addressForm = setAddressForm.fill(new SetAddress(cart.getShippingAddress()));
}
if (shippingForm == null) {
shippingForm = setShippingForm.fill(new SetShippingMethod(cart.getShippingInfo()));
}
// Pre-select a shipping method
if (cart.getShippingAddress() != null && cart.getShippingInfo() == null) {
String shippingMethodId = getDefaultShippingMethod(getShippingMethods()).getId();
setCurrentCart(sphere().currentCart().setShippingMethod(ShippingMethod.reference(shippingMethodId)));
}
return checkouts.render(getCurrentCart(), getAddressBook(), addressForm, shippingForm, page);
}
}