11 Commits

13 changed files with 90 additions and 29 deletions

View File

@ -1,6 +1,5 @@
package org.hso.ecommerce.components; package org.hso.ecommerce.components;
import org.hso.ecommerce.entities.booking.PaymentMethod;
import org.hso.ecommerce.entities.shop.Address; import org.hso.ecommerce.entities.shop.Address;
import org.hso.ecommerce.entities.user.User; import org.hso.ecommerce.entities.user.User;
import org.hso.ecommerce.repos.user.UserRepository; import org.hso.ecommerce.repos.user.UserRepository;
@ -26,8 +25,7 @@ public class AdminInitializer {
firstAdmin.created = new Timestamp(System.currentTimeMillis()); firstAdmin.created = new Timestamp(System.currentTimeMillis());
firstAdmin.defaultDeliveryAddress = new Address(); firstAdmin.defaultDeliveryAddress = new Address();
firstAdmin.defaultDeliveryAddress.name = "admin"; firstAdmin.defaultDeliveryAddress.name = "admin";
firstAdmin.defaultPayment = new PaymentMethod(); firstAdmin.defaultPayment = null;
firstAdmin.defaultPayment.creditCardNumber = ""; //set empty number
firstAdmin.email = "admin"; firstAdmin.email = "admin";
firstAdmin.isActive = true; firstAdmin.isActive = true;
firstAdmin.isEmployee = true; firstAdmin.isEmployee = true;

View File

@ -1,6 +1,5 @@
package org.hso.ecommerce.controller; package org.hso.ecommerce.controller;
import org.hso.ecommerce.entities.booking.PaymentMethod;
import org.hso.ecommerce.entities.shop.Address; import org.hso.ecommerce.entities.shop.Address;
import org.hso.ecommerce.entities.user.User; import org.hso.ecommerce.entities.user.User;
import org.hso.ecommerce.repos.user.UserRepository; import org.hso.ecommerce.repos.user.UserRepository;
@ -47,7 +46,7 @@ public class RegisterController {
newUser.email = username; newUser.email = username;
newUser.isEmployee = false; newUser.isEmployee = false;
newUser.salutation = salutation; newUser.salutation = salutation;
newUser.defaultPayment = PaymentMethod.fromCreditCardNumber(""); newUser.defaultPayment = null;
newUser.isActive = true; newUser.isActive = true;
newUser.created = new java.sql.Timestamp(System.currentTimeMillis()); newUser.created = new java.sql.Timestamp(System.currentTimeMillis());

View File

@ -37,6 +37,7 @@ public class ShopArticleController {
@GetMapping("/{id}") @GetMapping("/{id}")
public String shopArticlesById(Model model, public String shopArticlesById(Model model,
@RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart,
@PathVariable("id") Long id, @PathVariable("id") Long id,
HttpServletRequest request, HttpServletRequest request,
HttpServletResponse response HttpServletResponse response
@ -52,15 +53,14 @@ public class ShopArticleController {
} }
model.addAttribute("article", article); model.addAttribute("article", article);
if (warehouseBookingPositionSlotEntryRepository int inStock = warehouseBookingPositionSlotEntryRepository
.getByArticle(id) .getByArticle(id)
.stream() .stream()
.mapToInt(e -> e.newSumSlot) .mapToInt(e -> e.newSumSlot)
.sum() > 0) { //check if in Stock .sum();
model.addAttribute("inStock", true);
} else { model.addAttribute("inStock", Math.min(inStock, 10));
model.addAttribute("inStock", false); model.addAttribute("inCart", shoppingCart.getArticleCount(article));
}
List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(3, articleRepository.getAdvertisedArticles()); //get 3 advertised Articles List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(3, articleRepository.getAdvertisedArticles()); //get 3 advertised Articles
model.addAttribute("commercialArticles", commercialArticles); model.addAttribute("commercialArticles", commercialArticles);
@ -78,7 +78,7 @@ public class ShopArticleController {
@RequestParam(value = "set_amount", required = false) Boolean setAmount, @RequestParam(value = "set_amount", required = false) Boolean setAmount,
@RequestParam("fastcheckout") Boolean fastcheckout @RequestParam("fastcheckout") Boolean fastcheckout
) { ) {
Article article = articleRepository.findArticleById(id); Article article = articleRepository.findById(id).orElse(null);
if (article == null) { if (article == null) {
request.setAttribute("error", "Der Artikel wurde nicht gefunden."); request.setAttribute("error", "Der Artikel wurde nicht gefunden.");

View File

@ -57,12 +57,26 @@ public class ShopCheckoutController {
CheckoutListTotals totals = new CheckoutListTotals(); CheckoutListTotals totals = new CheckoutListTotals();
ArrayList<CheckoutListItem> items = new ArrayList<>(); ArrayList<CheckoutListItem> items = new ArrayList<>();
boolean inValid = false;
for (ShoppingCart.ShoppingCartItem item : shoppingCart.getItems()) { for (ShoppingCart.ShoppingCartItem item : shoppingCart.getItems()) {
Article article = articleRepository.findById(item.getArticleId()).get(); Article article = articleRepository.findById(item.getArticleId()).get();
int inStock = wbeseRepo
.getByArticle(item.getArticleId())
.stream()
.mapToInt(e -> e.newSumSlot)
.sum();
totals.addItem(article, item.getAmount()); totals.addItem(article, item.getAmount());
items.add(new CheckoutListItem(item.getAmount(), article)); items.add(new CheckoutListItem(item.getAmount(), Math.min(inStock, 10), article));
if (item.getAmount() > inStock) {
inValid = true;
} }
}
request.setAttribute("inValid", inValid);
request.setAttribute("checkoutItems", items); request.setAttribute("checkoutItems", items);
request.setAttribute("checkoutTotals", totals); request.setAttribute("checkoutTotals", totals);
@ -87,11 +101,13 @@ public class ShopCheckoutController {
public int amount; public int amount;
public Article article; public Article article;
public int total; public int total;
public int inStock;
public CheckoutListItem(int amount, Article article) { public CheckoutListItem(int amount, int inStock, Article article) {
this.amount = amount; this.amount = amount;
this.article = article; this.article = article;
this.total = amount * article.getPriceGross(); this.total = amount * article.getPriceGross();
this.inStock = inStock;
} }
} }
@ -140,6 +156,11 @@ public class ShopCheckoutController {
bookingRepository.saveAll(result.bookings); bookingRepository.saveAll(result.bookings);
warehouseBookingRepository.save(result.warehouseBooking); warehouseBookingRepository.save(result.warehouseBooking);
if (user.defaultPayment == null) {
user.defaultPayment = PaymentMethod.fromCreditCardNumber(cardnumber);
userRepository.save(user);
}
shoppingCart.clear(); shoppingCart.clear();
} catch (CreateOrderAction.ArticleNotInStockException e) { } catch (CreateOrderAction.ArticleNotInStockException e) {

View File

@ -42,9 +42,8 @@ public class ShopSearchController {
List<Article> articles = articleRepository.getArticlesByCategory(category); //search by Category List<Article> articles = articleRepository.getArticlesByCategory(category); //search by Category
model.addAttribute("articles", articles); model.addAttribute("articles", articles);
} else { } else {
request.setAttribute("error", "Es wurden keine Suchparameter angegeben."); List<Article> articles = SearchByTermAction.searchByTerm("", articleRepository);
response.setStatus(HttpServletResponse.SC_NOT_FOUND); model.addAttribute("articles", articles);
return "error/404";
} }
// Show term in search box // Show term in search box

View File

@ -69,6 +69,16 @@ public class ShoppingCart {
items.removeIf(i -> i.getAmount() <= 0); items.removeIf(i -> i.getAmount() <= 0);
} }
public int getArticleCount(Article article) {
for (ShoppingCartItem i : items) {
if (i.getArticleId() == article.id) {
return i.amount;
}
}
return 0;
}
public static class ShoppingCartItem { public static class ShoppingCartItem {
private int amount; private int amount;
private final long articleId; private final long articleId;

View File

@ -14,6 +14,7 @@ spring.jpa.show-sql=true
#spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql #spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql
#spring.session.jdbc.table-name=SPRING_SESSION #spring.session.jdbc.table-name=SPRING_SESSION
#server.servlet.session.persistent=true #server.servlet.session.persistent=true
server.servlet.session.timeout=48h
# ---------------------------------------- # ----------------------------------------
# WEB PROPERTIES # WEB PROPERTIES
spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-file-size=10MB

View File

@ -380,7 +380,7 @@ button, .button {
/* box-shadow: var(--s-0-secondary); */ /* box-shadow: var(--s-0-secondary); */
} }
button:active, .button:active { button:enabled:active, .button:active {
background-color: var(--c-primary-highlight); background-color: var(--c-primary-highlight);
} }
@ -392,6 +392,10 @@ button,
transition: background-color 0.1s ease-out; transition: background-color 0.1s ease-out;
} }
button:disabled {
filter: grayscale(100%);
}
label { label {
display: block; display: block;
min-width: 10em; min-width: 10em;
@ -761,6 +765,7 @@ input[type="number"]:focus {
.error { .error {
background-color: var(--c-error); background-color: var(--c-error);
color: var(--c-base);
text-align: center; text-align: center;
font-size: var(--u0); font-size: var(--u0);
} }

View File

@ -19,7 +19,8 @@
</div> </div>
<div> <div>
<label for="username">Email Adresse</label> <label for="username">Email Adresse</label>
<input class="full-width" type="text" name="username" placeholder="Email Adresse" id="username" required> <input class="full-width" type="text" name="username" placeholder="Email Adresse" id="username"
pattern="[^@\s]+@[^\.\s]+\.[^\s]+" required>
</div> </div>
<div> <div>
<label for="password">Passwort</label> <label for="password">Passwort</label>

View File

@ -38,17 +38,28 @@
th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span> th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
</h2> </h2>
<div> <div>
<input type="hidden" name="set_amount" value="true"/>
<label class="nolinebreak">Menge:</label> <label class="nolinebreak">Menge:</label>
<select name="quantity" size="1"> <select name="quantity" size="1">
<option th:each="quantity : ${#numbers.sequence(1,10)}" <option th:if="${inCart > 0}" th:value="${inCart}" th:text="${inCart}"
selected></option>
<option th:if="${inCart > 0}" value="0">Entfernen</option>
<option th:if="${inStock > 0}" th:each="quantity : ${#numbers.sequence(1,inStock)}"
th:value="${quantity}" th:value="${quantity}"
th:text="${quantity}"></option> th:text="${quantity}"></option>
</select> </select>
</div> </div>
<h3 class="no-margin secondarytext" th:text="${inStock} ? 'AUF LAGER' : 'NICHT AUF LAGER'"></h3> <h3 class="no-margin secondarytext"
<button class="no-margin secondary" name="fastcheckout" value="false">In den Einkaufswagen th:text="${inStock > 0} ? 'AUF LAGER' : 'NICHT AUF LAGER'"></h3>
<button th:if="${inCart == 0}" class="no-margin secondary" name="fastcheckout" value="false"
th:disabled="${inStock==0}">In den Einkaufswagen
</button>
<button th:if="${inCart > 0}" class="no-margin secondary" name="fastcheckout" value="false"
th:disabled="${inStock==0}">Anzahl im Einkaufswagen ändern
</button>
<button class="no-margin" name="fastcheckout" value="true" th:disabled="${inStock==0}">Schneller
Checkout
</button> </button>
<button class="no-margin" name="fastcheckout" value="true">Schneller Checkout</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -58,12 +58,19 @@
<select name="quantity" size="1"> <select name="quantity" size="1">
<option th:value="${item.amount}" th:text="${item.amount}" selected></option> <option th:value="${item.amount}" th:text="${item.amount}" selected></option>
<option value="0">Entfernen</option> <option value="0">Entfernen</option>
<option th:each="quantity : ${#numbers.sequence(1,10)}" <option th:if="${item.inStock > 0}"
th:each="quantity : ${#numbers.sequence(1,item.inStock)}"
th:value="${quantity}" th:value="${quantity}"
th:text="${quantity}"></option> th:text="${quantity}"></option>
</select> </select>
<button class="small">Ändern</button> <button class="small">Ändern</button>
</form> </form>
</td>
</tr>
<tr th:if="${item.amount > item.inStock}">
<td class="error" colspan="4">
Die gewählte Anzahl des Artikels ist leider derzeit nicht lieferbar.
</td> </td>
</tr> </tr>
<th:block> <th:block>
@ -97,6 +104,12 @@ Musterstraße 4
th:value="${user.defaultPayment != null ? user.defaultPayment.creditCardNumber : ''}" th:value="${user.defaultPayment != null ? user.defaultPayment.creditCardNumber : ''}"
pattern="[0-9]{6,16}" pattern="[0-9]{6,16}"
required/> required/>
<p th:if="${user.defaultPayment == null}" class="secondary card">
Da dies Ihre erste Bestellung ist, wird die Kreditkarte als Standartzahlungsmittel hinterlegt.
Sie kann unter den Nutzereinstellungen gelöscht oder geändert werden.
</p>
<small th:if="${user.defaultPayment != null}" class="no-padding">Die Standardkreditkarte kann unter
den <a href="/user/settings">Nutzereinstellungen</a> gelöscht oder geändert werden.</small>
</fieldset> </fieldset>
</div> </div>
<div> <div>
@ -132,7 +145,9 @@ Musterstraße 4
</table> </table>
</div> </div>
<div th:if="${user}"> <div th:if="${user}">
<button class=" no-margin secondary full-width">jetzt kostenpflichtig bestellen</button> <button class=" no-margin secondary full-width" th:disabled="${inValid}">jetzt kostenpflichtig
bestellen
</button>
</div> </div>
<div th:unless="${user}"> <div th:unless="${user}">
<a th:href="@{/login}" class="button secondary no-margin full-width">Einloggen und fortfahren.</a> <a th:href="@{/login}" class="button secondary no-margin full-width">Einloggen und fortfahren.</a>

View File

@ -21,13 +21,14 @@
<main class="sidebar-layout content-width"> <main class="sidebar-layout content-width">
<nav th:replace="fragments/customer :: sidebar"></nav> <nav th:replace="fragments/customer :: sidebar"></nav>
<div class="content-width"> <div class="content-width">
<form method="POST" th:action="@{/user/settings/changeMail}"> <form class="detailflex" method="POST" th:action="@{/user/settings/changeMail}">
<div> <div>
<h2> Login Daten </h2> <h2> Login Daten </h2>
</div> </div>
<div> <div>
<div class="input-icon"> <div class="input-icon">
<input class="full-width" type="text" name="email" th:value="${user.email}" required/> <input class="full-width" type="text" name="email" th:value="${user.email}"
pattern="[^@\s]+@[^\.\s]+\.[^\s]+" required/>
<button> Email-Adresse ändern</button> <button> Email-Adresse ändern</button>
</div> </div>
</div> </div>

View File

@ -31,7 +31,7 @@
"shouldBeAdvertised": false "shouldBeAdvertised": false
}, },
{ {
"title": "Aeroheat CYLON PC-Geh<EFBFBD>use", "title": "Aeroheat CYLON PC-Gehäuse",
"manufacturer": "Aeroheat", "manufacturer": "Aeroheat",
"articleNumber": "acpcg", "articleNumber": "acpcg",
"vatPercent": 19, "vatPercent": 19,