diff --git a/src/main/java/ch/wisv/events/core/model/order/Order.java b/src/main/java/ch/wisv/events/core/model/order/Order.java index b2351e2a..7042b40d 100644 --- a/src/main/java/ch/wisv/events/core/model/order/Order.java +++ b/src/main/java/ch/wisv/events/core/model/order/Order.java @@ -61,6 +61,12 @@ public class Order { @NotNull private Double vat = 0.0; + /** + * Administration costs of the order. + */ + @NotNull + private Double administrationCosts = 0.0; + /** * Field products list of Products in the Order. */ @@ -137,6 +143,7 @@ public void updateOrderAmount() { this.getOrderProducts().stream() .mapToDouble(orderProduct -> orderProduct.getProduct().getCost() * orderProduct.getAmount()) .sum() + + this.administrationCosts ); this.setVat(Math.round(this.getOrderProducts().stream() diff --git a/src/main/java/ch/wisv/events/core/service/order/OrderServiceImpl.java b/src/main/java/ch/wisv/events/core/service/order/OrderServiceImpl.java index 80ff391c..12974310 100644 --- a/src/main/java/ch/wisv/events/core/service/order/OrderServiceImpl.java +++ b/src/main/java/ch/wisv/events/core/service/order/OrderServiceImpl.java @@ -37,6 +37,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; @@ -79,6 +80,12 @@ public class OrderServiceImpl implements OrderService { */ private final TicketService ticketService; + /** + * Possible administration costs value + */ + @Value("${administrationCosts}") + private double administrationCosts; + /** * Constructor OrderServiceImpl creates a new OrderServiceImpl instance. * @@ -155,6 +162,10 @@ public Order createOrderByOrderProductDto(OrderProductDto orderProductDto) throw if (values.getValue() > 0) { Product product = productService.getByKey(values.getKey()); + if(product.getCost() > 0){ + order.setAdministrationCosts(administrationCosts); + } + order.addOrderProduct(new OrderProduct(product, product.getCost(), values.getValue())); } } diff --git a/src/main/java/ch/wisv/events/core/service/order/OrderValidationServiceImpl.java b/src/main/java/ch/wisv/events/core/service/order/OrderValidationServiceImpl.java index bf77002c..dfd04770 100644 --- a/src/main/java/ch/wisv/events/core/service/order/OrderValidationServiceImpl.java +++ b/src/main/java/ch/wisv/events/core/service/order/OrderValidationServiceImpl.java @@ -18,6 +18,7 @@ import java.time.LocalDateTime; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; /** @@ -38,6 +39,12 @@ public class OrderValidationServiceImpl implements OrderValidationService { /** EventService. */ private final EventService eventService; + /** + * Possible administration costs value + */ + @Value("${administrationCosts}") + private double administrationCosts; + /** * OrderValidationServiceImpl constructor. * @@ -133,10 +140,18 @@ private void assertDefaultOrderChecks(Order order) throws OrderInvalidException throw new OrderInvalidException("Order amount can not be null"); } + Double administrationCostShouldBe = order.getOrderProducts().stream() + .mapToDouble(orderProduct -> orderProduct.getProduct().getCost() * orderProduct.getAmount()) + .anyMatch(c -> c > 0.0) ? administrationCosts : 0.0; + + if (!order.getAdministrationCosts().equals(administrationCostShouldBe)) { + throw new OrderInvalidException("Order administration costs does not match"); + } + Double amountShouldBe = order.getOrderProducts() .stream() .mapToDouble(orderProduct -> orderProduct.getPrice() * orderProduct.getAmount()) - .sum(); + .sum() + order.getAdministrationCosts(); if (!order.getAmount().equals(amountShouldBe)) { throw new OrderInvalidException("Order amount does not match"); diff --git a/src/main/java/ch/wisv/events/utils/dev/data/OrderTestDataRunner.java b/src/main/java/ch/wisv/events/utils/dev/data/OrderTestDataRunner.java index 23bf469f..37a10fde 100644 --- a/src/main/java/ch/wisv/events/utils/dev/data/OrderTestDataRunner.java +++ b/src/main/java/ch/wisv/events/utils/dev/data/OrderTestDataRunner.java @@ -18,6 +18,7 @@ import java.util.UUID; import org.apache.commons.lang3.RandomStringUtils; import org.json.simple.JSONObject; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -48,6 +49,12 @@ public class OrderTestDataRunner extends TestDataRunner { /** TicketRepository. */ private final TicketRepository ticketRepository; + /** + * Possible administration costs value + */ + @Value("${administrationCosts}") + private double administrationCosts; + /** * Constructor EventTestDataRunner creates a new EventTestDataRunner instance. * @@ -102,6 +109,10 @@ private ch.wisv.events.core.model.order.Order createOrder(JSONObject jsonObject) orderProductRepository.saveAndFlush(orderProduct); + if(orderProduct.getPrice() > 0.0){ + order.setAdministrationCosts(administrationCosts); + } + order.addOrderProduct(orderProduct); order.getOrderProducts().forEach(x -> { x.getProduct().increaseSold(1); diff --git a/src/main/java/ch/wisv/events/webshop/controller/WebshopIndexController.java b/src/main/java/ch/wisv/events/webshop/controller/WebshopIndexController.java index a6c94c3d..59af9c36 100644 --- a/src/main/java/ch/wisv/events/webshop/controller/WebshopIndexController.java +++ b/src/main/java/ch/wisv/events/webshop/controller/WebshopIndexController.java @@ -32,6 +32,9 @@ public class WebshopIndexController extends WebshopController { /** Model attr of the OrderProductDTO. */ private static final String MODEL_ATTR_ORDER_PRODUCT = "orderProduct"; + /** Model attr administrationCosts. */ + private static final String MODEL_ATTR_ADMINISTRATION_COSTS = "administrationCosts"; + /** EventService. */ private final EventService eventService; @@ -45,6 +48,13 @@ public class WebshopIndexController extends WebshopController { @NotNull private String linkGTC; + /** + * Possible administration costs value + */ + @Value("${administrationCosts}") + @NotNull + private double administrationCosts; + /** * WebshopController constructor. * @@ -77,6 +87,7 @@ public String index(Model model) { model.addAttribute(MODEL_ATTR_CUSTOMER, authenticationService.getCurrentCustomer()); model.addAttribute(MODEL_ATTR_EVENTS, webshopService.filterEventProductNotSalable(upcoming)); model.addAttribute(MODEL_ATTR_ORDER_PRODUCT, new OrderProductDto()); + model.addAttribute(MODEL_ATTR_ADMINISTRATION_COSTS, administrationCosts); model.addAttribute("linkGTC", linkGTC); return "webshop/index"; @@ -96,6 +107,7 @@ public String index(Model model, @PathVariable String key) { model.addAttribute(MODEL_ATTR_CUSTOMER, authenticationService.getCurrentCustomer()); model.addAttribute(MODEL_ATTR_EVENT, webshopService.filterEventProductNotSalable(eventService.getByKey(key))); model.addAttribute(MODEL_ATTR_ORDER_PRODUCT, new OrderProductDto()); + model.addAttribute(MODEL_ATTR_ADMINISTRATION_COSTS, administrationCosts); return "webshop/event"; } catch (EventNotFoundException e) { diff --git a/src/main/java/ch/wisv/events/webshop/service/PaymentsServiceImpl.java b/src/main/java/ch/wisv/events/webshop/service/PaymentsServiceImpl.java index bbc7939f..6307542f 100644 --- a/src/main/java/ch/wisv/events/webshop/service/PaymentsServiceImpl.java +++ b/src/main/java/ch/wisv/events/webshop/service/PaymentsServiceImpl.java @@ -131,9 +131,7 @@ protected PaymentRequest createMolliePaymentRequestFromOrder(Order order) { String returnUrl = clientUri + "/return/" + order.getPublicReference(); String webhookUrl = clientUri + "/api/v1/orders/status"; - double value = order.getOrderProducts().stream() - .mapToDouble(op -> op.getPrice() * op.getAmount()) - .sum(); + double value = order.getAmount(); value = order.getPaymentMethod().calculateCostIncludingTransaction(value); Amount paymentAmount = Amount.builder().value(BigDecimal.valueOf(value).setScale(2, RoundingMode.CEILING)).currency("EUR").build(); diff --git a/src/main/resources/static/js/webshop/webshop.js b/src/main/resources/static/js/webshop/webshop.js index dcca7275..02cbf98a 100644 --- a/src/main/resources/static/js/webshop/webshop.js +++ b/src/main/resources/static/js/webshop/webshop.js @@ -75,6 +75,7 @@ var ShoppingBasket; var shoppingBasketTable = ""; var shoppingBasketTotal = 0; var countItems = 0; + var administrationCosts = 0; $.each(ShoppingBasket.shoppingBasket, function (index, product) { var rowBlueprint = "%s%s€ %s"; @@ -90,8 +91,20 @@ var ShoppingBasket; countItems += product.amount; shoppingBasketTotal += product.amount * product.cost; + + if (product.cost > 0) { + administrationCosts = administrationCostsSetting; + } }); + var rowBlueprint = "Administration costs€ %s"; + + shoppingBasketTable += vsprintf(rowBlueprint, [ + parseFloat(Math.round(administrationCosts * 100) / 100).toFixed(2).replace(".", ",") + ]); + + shoppingBasketTotal += administrationCosts; + $("#shoppingBasketTable").html(shoppingBasketTable); $("#shoppingBasketCount").html(countItems); $("#shoppingBasketTotal").html("€ " + parseFloat(Math.round(shoppingBasketTotal * 100) / 100).toFixed(2).replace(".", ",")); diff --git a/src/main/resources/static/js/webshop/webshop.min.js b/src/main/resources/static/js/webshop/webshop.min.js index 90c0b6e6..94f8c223 100644 --- a/src/main/resources/static/js/webshop/webshop.min.js +++ b/src/main/resources/static/js/webshop/webshop.min.js @@ -1 +1 @@ -var ShoppingBasket;!function(t){ShoppingBasket={LOCAL_STORAGE_SHOPPING_BASKET:"shoppingBasket",toast_id:0,shoppingBasket:[],init:function(){null!==Storages.localStorage.get(ShoppingBasket.LOCAL_STORAGE_SHOPPING_BASKET)&&(ShoppingBasket.shoppingBasket=Storages.localStorage.get(ShoppingBasket.LOCAL_STORAGE_SHOPPING_BASKET)),ShoppingBasket.__createShoppingBasketTable(),ShoppingBasket.binds()},binds:function(){t("#emptyShoppingBasket").on("click",ShoppingBasket.__emptyShoppingBasket),t("#orderForm").on("submit",ShoppingBasket.__beforeShoppingBasketSubmit),t(".btn-shopping-basket").on("click",ShoppingBasket.__addProductToShoppingBasket)},__beforeShoppingBasketSubmit:function(){t.each(ShoppingBasket.shoppingBasket,function(e,a){t("#products").append(vsprintf('',[a.key,a.amount])),0})},__emptyShoppingBasket:function(){ShoppingBasket.shoppingBasket=[],Storages.localStorage.set(ShoppingBasket.LOCAL_STORAGE_SHOPPING_BASKET,[]),ShoppingBasket.__createShoppingBasketTable()},__addProductToShoppingBasket:function(e){e.preventDefault();var a=ShoppingBasket.__indexProductContains(t(e.target).data("product-key"),ShoppingBasket.shoppingBasket);if(a>=0){if(!(ShoppingBasket.shoppingBasket[a].amount%s%s€ %s",[o.title,o.key,o.amount,o.key,parseFloat(Math.round(o.amount*o.cost*100)/100).toFixed(2).replace(".",",")]),n+=o.amount,a+=o.amount*o.cost}),t("#shoppingBasketTable").html(e),t("#shoppingBasketCount").html(n),t("#shoppingBasketTotal").html("€ "+parseFloat(Math.round(100*a)/100).toFixed(2).replace(".",",")),t(".increaseBasketAmount").on("click",ShoppingBasket.__increaseProductAmount),t(".decreaseBasketAmount").on("click",ShoppingBasket.__decreaseProductAmount)}},__increaseProductAmount:function(e){e.preventDefault();var a=ShoppingBasket.__indexProductContains(t(e.currentTarget).data("productKey"),ShoppingBasket.shoppingBasket);ShoppingBasket.shoppingBasket[a].amount++,Storages.localStorage.set(ShoppingBasket.LOCAL_STORAGE_SHOPPING_BASKET,ShoppingBasket.shoppingBasket),ShoppingBasket.__createShoppingBasketTable()},__decreaseProductAmount:function(e){e.preventDefault();var a=ShoppingBasket.__indexProductContains(t(e.currentTarget).data("productKey"),ShoppingBasket.shoppingBasket);ShoppingBasket.shoppingBasket[a].amount>1?ShoppingBasket.shoppingBasket[a].amount--:ShoppingBasket.shoppingBasket.splice(a,1),Storages.localStorage.set(ShoppingBasket.LOCAL_STORAGE_SHOPPING_BASKET,ShoppingBasket.shoppingBasket),ShoppingBasket.__createShoppingBasketTable()},__createEmptyShoppingBasketTable:function(){t("#shoppingBasketCount").html(0),t("#shoppingBasketTable").html("Shopping basket is empty!"),t("#shoppingBasketTotal").html("")},__indexProductContains:function(t,e){for(var a=0;a',[n.key,n.amount])),e++})},__emptyShoppingBasket:function(){ShoppingBasket.shoppingBasket=[],Storages.localStorage.set(ShoppingBasket.LOCAL_STORAGE_SHOPPING_BASKET,[]),ShoppingBasket.__createShoppingBasketTable()},__addProductToShoppingBasket:function(e){e.preventDefault();var a=ShoppingBasket.__indexProductContains(t(e.target).data("product-key"),ShoppingBasket.shoppingBasket);if(a>=0){if(!(ShoppingBasket.shoppingBasket[a].amount%s%s€ %s",[p.title,p.key,p.amount,p.key,parseFloat(Math.round(p.amount*p.cost*100)/100).toFixed(2).replace(".",",")]),n+=p.amount,a+=p.amount*p.cost,p.cost>0&&(o=administrationCostsSetting)}),e+=vsprintf("Administration costs€ %s",[parseFloat(Math.round(100*o)/100).toFixed(2).replace(".",",")]),a+=o,t("#shoppingBasketTable").html(e),t("#shoppingBasketCount").html(n),t("#shoppingBasketTotal").html("€ "+parseFloat(Math.round(100*a)/100).toFixed(2).replace(".",",")),t(".increaseBasketAmount").on("click",ShoppingBasket.__increaseProductAmount),t(".decreaseBasketAmount").on("click",ShoppingBasket.__decreaseProductAmount)}},__increaseProductAmount:function(e){e.preventDefault();var a=ShoppingBasket.__indexProductContains(t(e.currentTarget).data("productKey"),ShoppingBasket.shoppingBasket);ShoppingBasket.shoppingBasket[a].amount++,Storages.localStorage.set(ShoppingBasket.LOCAL_STORAGE_SHOPPING_BASKET,ShoppingBasket.shoppingBasket),ShoppingBasket.__createShoppingBasketTable()},__decreaseProductAmount:function(e){e.preventDefault();var a=ShoppingBasket.__indexProductContains(t(e.currentTarget).data("productKey"),ShoppingBasket.shoppingBasket);ShoppingBasket.shoppingBasket[a].amount>1?ShoppingBasket.shoppingBasket[a].amount--:ShoppingBasket.shoppingBasket.splice(a,1),Storages.localStorage.set(ShoppingBasket.LOCAL_STORAGE_SHOPPING_BASKET,ShoppingBasket.shoppingBasket),ShoppingBasket.__createShoppingBasketTable()},__createEmptyShoppingBasketTable:function(){t("#shoppingBasketCount").html(0),t("#shoppingBasketTable").html("Shopping basket is empty!"),t("#shoppingBasketTotal").html("")},__indexProductContains:function(t,e){for(var a=0;aProducts + + Administration costs + + + diff --git a/src/main/resources/templates/mail/order-reservation.html b/src/main/resources/templates/mail/order-reservation.html index 3ad98825..5c6e295d 100644 --- a/src/main/resources/templates/mail/order-reservation.html +++ b/src/main/resources/templates/mail/order-reservation.html @@ -324,6 +324,20 @@ € 2,00 + + + Administration costs + + + + + + diff --git a/src/main/resources/templates/mail/order.html b/src/main/resources/templates/mail/order.html index dbaf3bd8..cfaafd22 100644 --- a/src/main/resources/templates/mail/order.html +++ b/src/main/resources/templates/mail/order.html @@ -432,6 +432,20 @@

Receipt

style="font-family: Arial, sans-serif;color: #5e5e5e;font-size: 16px;text-align: left;border-collapse: collapse;background-color: #f3f3f3;padding: 5px;"> + + + Administration costs + + + + + + diff --git a/src/main/resources/templates/sales/sell/order/index.html b/src/main/resources/templates/sales/sell/order/index.html index f8fcb0dc..7163faf1 100644 --- a/src/main/resources/templates/sales/sell/order/index.html +++ b/src/main/resources/templates/sales/sell/order/index.html @@ -70,6 +70,11 @@ + + Administration costs + + diff --git a/src/main/resources/templates/webshop/checkout/index.html b/src/main/resources/templates/webshop/checkout/index.html index 8f087bf3..997b949f 100644 --- a/src/main/resources/templates/webshop/checkout/index.html +++ b/src/main/resources/templates/webshop/checkout/index.html @@ -62,6 +62,11 @@

Order overview

+ + Administration costs + + + diff --git a/src/main/resources/templates/webshop/event.html b/src/main/resources/templates/webshop/event.html index c1f8d922..e5165dad 100644 --- a/src/main/resources/templates/webshop/event.html +++ b/src/main/resources/templates/webshop/event.html @@ -218,6 +218,11 @@