implement checkout for non logged in users.
This commit is contained in:
parent
7d83d723c1
commit
d2bf6e8c52
|
@ -63,6 +63,7 @@ public class ShopArticleController {
|
|||
@RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart,
|
||||
@PathVariable("id") Long id,
|
||||
@RequestParam("quantity") Integer quantity,
|
||||
@RequestParam(value = "set_amount", required = false) Boolean setAmount,
|
||||
@RequestParam("fastcheckout") Boolean fastcheckout
|
||||
) {
|
||||
|
||||
|
@ -71,12 +72,16 @@ public class ShopArticleController {
|
|||
throw new RuntimeException("Article not found!");
|
||||
}
|
||||
|
||||
shoppingCart.addArticle(article.get(), quantity);
|
||||
if (setAmount != null && setAmount) {
|
||||
shoppingCart.setArticleCount(article.get(), quantity);
|
||||
} else {
|
||||
shoppingCart.addArticle(article.get(), quantity);
|
||||
}
|
||||
|
||||
if (!fastcheckout) {
|
||||
return "shop/articles/post_add";
|
||||
} else {
|
||||
return "shop/checkout";
|
||||
return "redirect:/shop/checkout";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,73 @@
|
|||
package org.hso.ecommerce.controller.shop;
|
||||
|
||||
import org.hso.ecommerce.entities.shop.Article;
|
||||
import org.hso.ecommerce.entities.shop.ShoppingCart;
|
||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.ArrayList;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/shop/")
|
||||
public class ShopCheckoutController {
|
||||
|
||||
@Autowired
|
||||
private final ArticleRepository articleRepository = null;
|
||||
|
||||
@GetMapping("/checkout")
|
||||
public String shopCheckout(HttpSession session, HttpServletRequest request) {
|
||||
public String shopCheckout(HttpSession session,
|
||||
HttpServletRequest request,
|
||||
@RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart) {
|
||||
session.setAttribute("afterLogin", request.getRequestURI());
|
||||
|
||||
CheckoutListTotals totals = new CheckoutListTotals();
|
||||
ArrayList<CheckoutListItem> items = new ArrayList<>();
|
||||
for (ShoppingCart.ShoppingCartItem item : shoppingCart.getItems()) {
|
||||
Article article = articleRepository.findById(item.getArticleId()).get();
|
||||
|
||||
totals.addItem(article, item.getAmount());
|
||||
items.add(new CheckoutListItem(item.getAmount(), article));
|
||||
}
|
||||
|
||||
request.setAttribute("checkoutItems", items);
|
||||
request.setAttribute("checkoutTotals", totals);
|
||||
|
||||
return "shop/checkout";
|
||||
}
|
||||
|
||||
public static class CheckoutListTotals {
|
||||
public int net;
|
||||
public TreeMap<Integer, Integer> vatAmounts = new TreeMap<>();
|
||||
public int total;
|
||||
|
||||
void addItem(Article article, int amount) {
|
||||
net += article.shopPricePerUnitNetCent * amount;
|
||||
Integer vatPos = vatAmounts.getOrDefault(article.related.vatPercent, 0) + article.getVat() * amount;
|
||||
vatAmounts.put(article.related.vatPercent, vatPos);
|
||||
total += article.getPriceGross() * amount;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CheckoutListItem {
|
||||
public int amount;
|
||||
public Article article;
|
||||
public int total;
|
||||
|
||||
public CheckoutListItem(int amount, Article article) {
|
||||
this.amount = amount;
|
||||
this.article = article;
|
||||
this.total = amount * article.getPriceGross();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/checkoutFinish")
|
||||
public String shopCheckoutFinish() {
|
||||
return "shop/checkoutFinish";
|
||||
|
|
|
@ -37,4 +37,12 @@ public class Article {
|
|||
@ManyToMany
|
||||
@JoinTable(name = "article_categories_bindings")
|
||||
public Set<Category> categories = new HashSet<>();
|
||||
|
||||
public int getVat() {
|
||||
return (shopPricePerUnitNetCent * related.vatPercent) / 100;
|
||||
}
|
||||
|
||||
public int getPriceGross() {
|
||||
return shopPricePerUnitNetCent + getVat();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.hso.ecommerce.entities.shop;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
// Not a db entity. Just for session storage
|
||||
public class ShoppingCart {
|
||||
|
@ -13,6 +14,10 @@ public class ShoppingCart {
|
|||
items = new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<ShoppingCartItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
int count = 0;
|
||||
|
||||
|
@ -40,7 +45,25 @@ public class ShoppingCart {
|
|||
items.add(new ShoppingCartItem(quantity, article));
|
||||
}
|
||||
|
||||
private static class ShoppingCartItem {
|
||||
public void setArticleCount(Article article, Integer quantity) {
|
||||
this.revision++;
|
||||
|
||||
boolean found = false;
|
||||
for (ShoppingCartItem i : items) {
|
||||
if (i.getArticleId() == article.id) {
|
||||
i.setAmount(quantity);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
items.add(new ShoppingCartItem(quantity, article));
|
||||
}
|
||||
|
||||
items.removeIf(i -> i.getAmount() == 0);
|
||||
}
|
||||
|
||||
public static class ShoppingCartItem {
|
||||
private int amount;
|
||||
private final long articleId;
|
||||
|
||||
|
@ -60,5 +83,9 @@ public class ShoppingCart {
|
|||
public long getArticleId() {
|
||||
return articleId;
|
||||
}
|
||||
|
||||
public void setAmount(Integer amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
CREATE TABLE "customers" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"lastname" TEXT,
|
||||
"firstname" TEXT,
|
||||
"username" TEXT,
|
||||
"password" TEXT
|
||||
);
|
|
@ -31,91 +31,31 @@
|
|||
<th>Menge</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-1.jpg}" class="s"/><a/></td>
|
||||
<td><a th:href="@{/shop/articles/4151}">Kamera<a/></td>
|
||||
<td>100,50 EUR</td>
|
||||
<td>
|
||||
<select size="1">
|
||||
<option value="1" selected>1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button class="small">Entfernen</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-2.jpg}" class="s"/><a/></td>
|
||||
<td><a th:href="@{/shop/articles/4151}">Earbuds<a/></td>
|
||||
<td>63,95 EUR</td>
|
||||
<td>
|
||||
<select size="1">
|
||||
<option value="1" selected>1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button>Entfernen</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-3.jpg}" class="s"/><a/></td>
|
||||
<td><a th:href="@{/shop/articles/4151}">USB-Magic Light<a/></td>
|
||||
<td>11,90 EUR</td>
|
||||
<td>
|
||||
<select size="1">
|
||||
<option value="1">1</option>
|
||||
<option value="2" selected>2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button>Entfernen</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-4.jpg}" class="s"/><a/></td>
|
||||
<td><a th:href="@{/shop/articles/4151}">3D Magic Stativ<a/></td>
|
||||
<td>15,99 EUR</td>
|
||||
<td>
|
||||
<select size="1">
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5" selected>5</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button>Entfernen</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-5.jpg}" class="s"/><a/></td>
|
||||
<td><a th:href="@{/shop/articles/4151}">Ersatzfernbedinung<a/></td>
|
||||
<td>7,95 EUR</td>
|
||||
<td>
|
||||
<select size="1">
|
||||
<option value="1" selected>1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button>Entfernen</button>
|
||||
</td>
|
||||
</tr>
|
||||
<th:block th:each="item : ${checkoutItems}">
|
||||
<tr>
|
||||
<td><a th:href="@{/shop/articles/{id}(id = ${item.article.id})}"><img
|
||||
th:src="@{/shop/articles/${item.article.id}/image.jpg}" class="s"/></a></td>
|
||||
<td><a th:href="@{/shop/articles/{id}(id = ${item.article.id})}"
|
||||
th:text="${item.article.title}"></a></td>
|
||||
<td><span th:text="${#numbers.formatDecimal(item.total, 1, 'POINT', 2, 'COMMA')}"></span> EUR</td>
|
||||
<td>
|
||||
<form method="POST" th:action="@{/shop/articles/{id}(id = ${item.article.id})}">
|
||||
<input type="hidden" name="fastcheckout" value="true"/>
|
||||
<input type="hidden" name="set_amount" value="true"/>
|
||||
<select name="quantity" size="1">
|
||||
<option th:value="${item.amount}" th:text="${item.amount}" selected></option>
|
||||
<option value="0">Entfernen</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
<button class="small">Ändern</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<th:block>
|
||||
</table>
|
||||
</div>
|
||||
<form method="POST" th:action="@{/shop/checkoutFinish}" style="min-width: 30em; max-width: 45em;">
|
||||
|
@ -151,23 +91,26 @@ Musterstraße 42
|
|||
<table>
|
||||
<tr>
|
||||
<th>Artikel (Netto)</th>
|
||||
<th>200,29 EUR</th>
|
||||
</tr>
|
||||
<tr th:if="${user}">
|
||||
<th>Bonuspunkte</th>
|
||||
<th>-5,00 EUR</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Umsatzsteuer (19%)</th>
|
||||
<th>35,00 EUR</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Umsatzsteuer (7%)</th>
|
||||
<th>2,50 EUR</th>
|
||||
<th><span
|
||||
th:text="${#numbers.formatDecimal(checkoutTotals.net, 1, 'POINT', 2, 'COMMA')}"></span>
|
||||
EUR
|
||||
</th>
|
||||
</tr>
|
||||
<th:block th:each="item : ${checkoutTotals.vatAmounts.entrySet()}">
|
||||
<tr>
|
||||
<th>Umsatzsteuer (<span th:text="${item.getKey()}"></span>%)</th>
|
||||
<th><span
|
||||
th:text="${#numbers.formatDecimal(item.getValue(), 1, 'POINT', 2, 'COMMA')}"></span>
|
||||
EUR
|
||||
</th>
|
||||
</tr>
|
||||
</th:block>
|
||||
<tr class="secondary">
|
||||
<th>Gesamt:</th>
|
||||
<th>240,79 EUR</th>
|
||||
<th><span
|
||||
th:text="${#numbers.formatDecimal(checkoutTotals.total, 1, 'POINT', 2, 'COMMA')}"></span>
|
||||
EUR
|
||||
</th>
|
||||
</tr>
|
||||
<tr th:if="${user}" class="secondary">
|
||||
<th colspan="2" class=" no-padding"></th>
|
||||
|
|
Reference in New Issue