Skip to content

Commit

Permalink
Merge pull request #500 from WISVCH/use-mollie-hosted-checkout
Browse files Browse the repository at this point in the history
Use Mollie Checkout
  • Loading branch information
robertdijk authored Jul 29, 2024
2 parents 6c5f18e + 28b633d commit 523e9c9
Show file tree
Hide file tree
Showing 9 changed files with 37 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public SalesExportSubmission() {
this.month = LocalDate.now().getMonthValue()-1;
}

this.includedPaymentMethods = Lists.newArrayList(PaymentMethod.IDEAL, PaymentMethod.SOFORT);
this.includedPaymentMethods = Lists.newArrayList(PaymentMethod.IDEAL, PaymentMethod.SOFORT, PaymentMethod.MOLLIE);

this.freeProductsIncluded = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public enum PaymentMethod {
*/
SOFORT("sofort", cost -> 1.01089 * cost + 0.3025),

/**
* User paid his order via Mollie.
*/
MOLLIE("mollie", cost -> cost),

/**
* User paid his order via another method.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ public String paymentOverview(Model model, RedirectAttributes redirect, @PathVar
);
}

return "webshop/payment/index";
if (orderService.containsOnlyReservable(order)) {
return "webshop/payment/index";
}

return "redirect:/checkout/" + order.getPublicReference() + "/payment/mollie";
} catch (EventsException e) {
redirect.addFlashAttribute(MODEL_ATTR_ERROR, e.getMessage());

Expand Down Expand Up @@ -117,29 +121,16 @@ public String paymentReservation(RedirectAttributes redirect, @PathVariable Stri
}

/**
* Payment method using iDeal.
*
* @param redirect of type RedirectAttributes
* @param key of type String
*
* @return String string
*/
@GetMapping("/ideal")
public String paymentIdeal(RedirectAttributes redirect, @PathVariable String key) {
return this.payment(redirect, key, PaymentMethod.IDEAL);
}

/**
* Payment method using SOFORT.
* Payment method using Mollie.
*
* @param redirect of type RedirectAttributes
* @param key of type String
*
* @return String string
*/
@GetMapping("/sofort")
public String paymentSofort(RedirectAttributes redirect, @PathVariable String key) {
return this.payment(redirect, key, PaymentMethod.SOFORT);
@GetMapping("/mollie")
public String paymentMollie(RedirectAttributes redirect, @PathVariable String key) {
return this.payment(redirect, key, PaymentMethod.MOLLIE);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

Expand Down Expand Up @@ -129,14 +128,6 @@ protected PaymentRequest createMolliePaymentRequestFromOrder(Order order) {

metadata.put("products", productString);

PaymentMethod method;

if (order.getPaymentMethod() == ch.wisv.events.core.model.order.PaymentMethod.IDEAL) {
method = PaymentMethod.IDEAL;
} else {
method = PaymentMethod.SOFORT;
}

String returnUrl = clientUri + "/return/" + order.getPublicReference();
String webhookUrl = clientUri + "/api/v1/orders/status";

Expand All @@ -148,7 +139,6 @@ protected PaymentRequest createMolliePaymentRequestFromOrder(Order order) {
Amount paymentAmount = Amount.builder().value(BigDecimal.valueOf(value).setScale(2, RoundingMode.CEILING)).currency("EUR").build();

return PaymentRequest.builder()
.method(Optional.of(List.of(method)))
.amount(paymentAmount)
.description("W.I.S.V. 'Christiaan Huygens'")
.consumerName(Optional.of(order.getOwner().getName()))
Expand Down
Binary file removed src/main/resources/static/images/icon-pay-later.jpg
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/resources/static/images/icon-pay-now.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 5 additions & 36 deletions src/main/resources/templates/webshop/payment/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,49 +52,18 @@ <h4 class="display-4">Select payment method</h4>
<div class="card-body h-100">
<div class="row h-100">
<div class="col-3 px-3">
<img class="img-thumbnail" th:src="@{/images/icon-ideal.png}" alt="">
<img class="img-thumbnail" th:src="@{/images/icon-pay-now.png}" alt="">
</div>
<div class="col-9 h-100">
<div class="row h-100">
<div class="col-12 align-self-start mb-4">
<h5 class="d-inline mt-0">IDEAL</h5> - Online payment using your
Dutch bank. Easy, fast and secure!<br>

<span class="text-info">(+ &euro; 0,35 transaction cost)</span>
</div>

<div class="col-12 align-self-end">
<a th:href="@{'/checkout/' + ${order.getPublicReference()} + '/payment/ideal'}"
class="btn btn-block btn-primary">
Pay with iDeal
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-6 mb-4">
<div class="card h-100">
<div class="card-body h-100">
<div class="row h-100">
<div class="col-3 px-3">
<img class="img-thumbnail" th:src="@{/images/icon-sofort.png}" alt="">
</div>
<div class="col-9 h-100">
<div class="row h-100">
<div class="col-12 align-self-start mb-4">
<h5 class="d-inline mt-0">SOFORT</h5> - Predominant online banking method in
countries across Europe.<br>

<span class="text-info">(+ &euro; 0,30 + 1,1% transaction cost)</span>
<h5 class="d-inline mt-0">Pay Online</h5> - Pay now using iDeal<br>
</div>

<div class="col-12 align-self-end">
<a th:href="@{'/checkout/' + ${order.getPublicReference()} + '/payment/sofort'}"
<a th:href="@{'/checkout/' + ${order.getPublicReference()} + '/payment/mollie'}"
class="btn btn-block btn-primary">
Pay with SOFORT
Pay Online
</a>
</div>
</div>
Expand All @@ -108,7 +77,7 @@ <h5 class="d-inline mt-0">SOFORT</h5> - Predominant online banking method in
<div class="card-body h-100">
<div class="row h-100">
<div class="col-3 px-3">
<img class="img-thumbnail" th:src="@{/images/icon-pay-later.jpg}" alt="">
<img class="img-thumbnail" th:src="@{/images/icon-pay-later.png}" alt="">
</div>
<div class="col-9 h-100">
<div class="row">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void testPaymentOverview() throws Exception {
.andExpect(status().isOk())
.andExpect(view().name("webshop/payment/index"))
.andExpect(model().attribute("order", order))
.andExpect(content().string(containsString("href=\"/checkout/" + order.getPublicReference() + "/payment/ideal\"")))
.andExpect(content().string(containsString("href=\"/checkout/" + order.getPublicReference() + "/payment/mollie\"")))
.andExpect(content().string(containsString("href=\"/checkout/" + order.getPublicReference() + "/payment/reservation\"")));
}

Expand All @@ -47,9 +47,8 @@ public void testNonReservableOrder() throws Exception {
order.getOrderProducts().get(0).getProduct().setReservable(false);

mockMvc.perform(get("/checkout/" + order.getPublicReference() + "/payment"))
.andExpect(status().isOk())
.andExpect(view().name("webshop/payment/index"))
.andExpect(content().string(not(containsString("href=\"/checkout/" + order.getPublicReference() + "/payment/reservation\""))));
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/checkout/" + order.getPublicReference() + "/payment/mollie"));
}

@Test
Expand Down Expand Up @@ -201,61 +200,61 @@ public void testPaymentReservationNotSuitableForCheckout() throws Exception {
public void testPaymentIdeal() throws Exception {
Order order = this.createPaymentOrder(OrderStatus.ASSIGNED, "events-webshop");

mockMvc.perform(get("/checkout/" + order.getPublicReference() + "/payment/ideal"))
mockMvc.perform(get("/checkout/" + order.getPublicReference() + "/payment/mollie"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("https://paymentURL.com"));

Order optional = orderService.getByReference(order.getPublicReference());

assertEquals(OrderStatus.PENDING, optional.getStatus());
assertEquals(PaymentMethod.IDEAL, optional.getPaymentMethod());
assertEquals(PaymentMethod.MOLLIE, optional.getPaymentMethod());
}

@Test
public void testPaymentIdealWrongStatus() throws Exception {
public void testPaymentMollieWrongStatus() throws Exception {
Order order = this.createPaymentOrder(OrderStatus.ANONYMOUS, "events-webshop");

this.requestPaymentCheckoutException(order, "/payment/ideal", "Order is not suitable for checkout!");
this.requestPaymentCheckoutException(order, "/payment/mollie", "Order is not suitable for checkout!");
}

@Test
public void testPaymentIdealWrongCreatedBy() throws Exception {
public void testPaymentMollieWrongCreatedBy() throws Exception {
Order order = this.createPaymentOrder(OrderStatus.ASSIGNED, "somebody");

this.requestPaymentCheckoutException(order, "/payment/ideal", "Order is not suitable for checkout!");
this.requestPaymentCheckoutException(order, "/payment/mollie", "Order is not suitable for checkout!");
}

@Test
public void testPaymentIdealWrongMissingOrder() throws Exception {
public void testPaymentMollieWrongMissingOrder() throws Exception {
Order order = this.createPaymentOrder(OrderStatus.ASSIGNED, "somebody");
order.setOwner(null);

this.requestPaymentCheckoutException(order, "/payment/ideal", "Order is not suitable for checkout!");
this.requestPaymentCheckoutException(order, "/payment/mollie", "Order is not suitable for checkout!");
}

@Test
public void testPaymentIdealMissingProducts() throws Exception {
public void testPaymentMollieMissingProducts() throws Exception {
Order order = this.createPaymentOrder(OrderStatus.ASSIGNED, "events-webshop");
order.setOrderProducts(new ArrayList<>());

this.requestPaymentCheckoutException(order, "/payment/ideal", "Order is not suitable for checkout!");
this.requestPaymentCheckoutException(order, "/payment/mollie", "Order is not suitable for checkout!");
}

@Test
public void testPaymentIdealNotFound() throws Exception {
public void testPaymentMollieNotFound() throws Exception {
Order order = new Order();

mockMvc.perform(get("/checkout/" + order.getPublicReference() + "/payment/ideal"))
mockMvc.perform(get("/checkout/" + order.getPublicReference() + "/payment/mollie"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/"))
.andExpect(flash().attribute("error", "Order with reference " + order.getPublicReference() + " not found!"));
}

@Test
public void testPaymentIdealNotSuitableForCheckout() throws Exception {
public void testPaymentMollieNotSuitableForCheckout() throws Exception {
Order order = this.createPaymentOrder(OrderStatus.PAID, "events-webshop");

this.requestPaymentCheckoutException(order, "/payment/ideal", "Order with status PAID is not suitable for checkout");
this.requestPaymentCheckoutException(order, "/payment/mollie", "Order with status PAID is not suitable for checkout");
}

private void requestPaymentCheckoutException(Order order, String path, String error) throws Exception {
Expand Down

0 comments on commit 523e9c9

Please sign in to comment.