WIP feature/listedArticles #15
|
@ -63,6 +63,7 @@ public class ShopArticleController {
|
||||||
@RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart,
|
@RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart,
|
||||||
@PathVariable("id") Long id,
|
@PathVariable("id") Long id,
|
||||||
@RequestParam("quantity") Integer quantity,
|
@RequestParam("quantity") Integer quantity,
|
||||||
|
@RequestParam(value = "set_amount", required = false) Boolean setAmount,
|
||||||
@RequestParam("fastcheckout") Boolean fastcheckout
|
@RequestParam("fastcheckout") Boolean fastcheckout
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -71,12 +72,16 @@ public class ShopArticleController {
|
||||||
throw new RuntimeException("Article not found!");
|
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) {
|
if (!fastcheckout) {
|
||||||
return "shop/articles/post_add";
|
return "shop/articles/post_add";
|
||||||
} else {
|
} else {
|
||||||
return "shop/checkout";
|
return "redirect:/shop/checkout";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,73 @@
|
||||||
package org.hso.ecommerce.controller.shop;
|
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.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/shop/")
|
@RequestMapping("/shop/")
|
||||||
public class ShopCheckoutController {
|
public class ShopCheckoutController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private final ArticleRepository articleRepository = null;
|
||||||
|
|
||||||
@GetMapping("/checkout")
|
@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());
|
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";
|
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")
|
@PostMapping("/checkoutFinish")
|
||||||
public String shopCheckoutFinish() {
|
public String shopCheckoutFinish() {
|
||||||
return "shop/checkoutFinish";
|
return "shop/checkoutFinish";
|
||||||
|
|
|
@ -37,4 +37,12 @@ public class Article {
|
||||||
@ManyToMany
|
@ManyToMany
|
||||||
@JoinTable(name = "article_categories_bindings")
|
@JoinTable(name = "article_categories_bindings")
|
||||||
public Set<Category> categories = new HashSet<>();
|
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;
|
package org.hso.ecommerce.entities.shop;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
// Not a db entity. Just for session storage
|
// Not a db entity. Just for session storage
|
||||||
public class ShoppingCart {
|
public class ShoppingCart {
|
||||||
|
@ -13,6 +14,10 @@ public class ShoppingCart {
|
||||||
items = new ArrayList<>();
|
items = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ShoppingCartItem> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
@ -40,7 +45,25 @@ public class ShoppingCart {
|
||||||
items.add(new ShoppingCartItem(quantity, article));
|
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 int amount;
|
||||||
private final long articleId;
|
private final long articleId;
|
||||||
|
|
||||||
|
@ -60,5 +83,9 @@ public class ShoppingCart {
|
||||||
public long getArticleId() {
|
public long getArticleId() {
|
||||||
return articleId;
|
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>Menge</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<th:block th:each="item : ${checkoutItems}">
|
||||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-1.jpg}" class="s"/><a/></td>
|
<tr>
|
||||||
<td><a th:href="@{/shop/articles/4151}">Kamera<a/></td>
|
<td><a th:href="@{/shop/articles/{id}(id = ${item.article.id})}"><img
|
||||||
<td>100,50 EUR</td>
|
th:src="@{/shop/articles/${item.article.id}/image.jpg}" class="s"/></a></td>
|
||||||
<td>
|
<td><a th:href="@{/shop/articles/{id}(id = ${item.article.id})}"
|
||||||
<select size="1">
|
th:text="${item.article.title}"></a></td>
|
||||||
<option value="1" selected>1</option>
|
<td><span th:text="${#numbers.formatDecimal(item.total, 1, 'POINT', 2, 'COMMA')}"></span> EUR</td>
|
||||||
<option value="2">2</option>
|
<td>
|
||||||
<option value="3">3</option>
|
<form method="POST" th:action="@{/shop/articles/{id}(id = ${item.article.id})}">
|
||||||
<option value="4">4</option>
|
<input type="hidden" name="fastcheckout" value="true"/>
|
||||||
<option value="5">5</option>
|
<input type="hidden" name="set_amount" value="true"/>
|
||||||
</select>
|
<select name="quantity" size="1">
|
||||||
</td>
|
<option th:value="${item.amount}" th:text="${item.amount}" selected></option>
|
||||||
<td>
|
<option value="0">Entfernen</option>
|
||||||
<button class="small">Entfernen</button>
|
<option value="1">1</option>
|
||||||
</td>
|
<option value="2">2</option>
|
||||||
</tr>
|
<option value="3">3</option>
|
||||||
<tr>
|
<option value="4">4</option>
|
||||||
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-2.jpg}" class="s"/><a/></td>
|
<option value="5">5</option>
|
||||||
<td><a th:href="@{/shop/articles/4151}">Earbuds<a/></td>
|
</select>
|
||||||
<td>63,95 EUR</td>
|
<button class="small">Ändern</button>
|
||||||
<td>
|
</form>
|
||||||
<select size="1">
|
</td>
|
||||||
<option value="1" selected>1</option>
|
</tr>
|
||||||
<option value="2">2</option>
|
<th:block>
|
||||||
<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>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<form method="POST" th:action="@{/shop/checkoutFinish}" style="min-width: 30em; max-width: 45em;">
|
<form method="POST" th:action="@{/shop/checkoutFinish}" style="min-width: 30em; max-width: 45em;">
|
||||||
|
@ -151,23 +91,26 @@ Musterstraße 42
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Artikel (Netto)</th>
|
<th>Artikel (Netto)</th>
|
||||||
<th>200,29 EUR</th>
|
<th><span
|
||||||
</tr>
|
th:text="${#numbers.formatDecimal(checkoutTotals.net, 1, 'POINT', 2, 'COMMA')}"></span>
|
||||||
<tr th:if="${user}">
|
EUR
|
||||||
<th>Bonuspunkte</th>
|
</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>
|
|
||||||
</tr>
|
</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">
|
<tr class="secondary">
|
||||||
<th>Gesamt:</th>
|
<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>
|
||||||
<tr th:if="${user}" class="secondary">
|
<tr th:if="${user}" class="secondary">
|
||||||
<th colspan="2" class=" no-padding"></th>
|
<th colspan="2" class=" no-padding"></th>
|
||||||
|
|
Reference in New Issue