Merge pull request 'WIP feature/listedArticles' (#15) from feature/listedArticles into master

Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
This commit is contained in:
Jannik 2020-05-15 19:48:21 +02:00
commit 2bbf8260f4
10 changed files with 352 additions and 120 deletions

View File

@ -46,12 +46,12 @@ public class RequestController {
return "login";
}
if (!user.get().validatePassword(password)) {
if (!user.get().validatePassword(password)) {
request.setAttribute("error", "Passwort falsch.");
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
return "login";
}
session.setAttribute("userId", user.get().getId());
if (gto != null && gto.startsWith("/")) {
@ -94,28 +94,7 @@ public class RequestController {
public String intern() {
return "intern/index";
}
@GetMapping("/intern/listedArticles/")
public String internListedArticles() {
return "intern/listedArticles/index";
}
@GetMapping("/intern/listedArticles/{id}")
public String internListedArticlesId() {
return "intern/listedArticles/id";
}
@GetMapping("/intern/articles/")
public String internArticles() {
return "intern/articles/index";
}
@GetMapping("/intern/articles/{id}")
public String internArticlesId() {
return "intern/articles/id";
}
@GetMapping("/intern/customers/")
public String internCustomers() {
return "intern/customers/index";

View File

@ -1,8 +1,268 @@
package org.hso.ecommerce.controller.intern;
import java.util.ArrayList;
import java.util.List;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.shop.Category;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.shop.CategoryRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.view.RedirectView;
@Controller
//@RequestMapping("...")
@RequestMapping("intern/articles")
public class InternArticleController {
@Autowired
private final ArticleRepository articleRepository = null;
@Autowired
private final WarehouseBookingPositionSlotEntryRepository warehouseEntryRepository = null;
@Autowired
private final CategoryRepository categoryRepository = null;
@GetMapping("/")
public String internListedArticles(Model model) {
List<UImodelArticles> totals = new ArrayList<UImodelArticles>();
for (Article article : articleRepository.findAll()) {
UImodelArticles tmp = new UImodelArticles();
tmp.addListedArticle(article, warehouseEntryRepository.getArticleStock(article.id).orElse(0));
totals.add(tmp);
}
model.addAttribute("ListedArticles", totals);
return "intern/listedArticles/index";
}
@GetMapping("/{id}")
public String internListedArticlesId(Model model, @PathVariable String id) {
int articleid = Integer.parseInt(id);
UImodelArticle total = new UImodelArticle();
total.addArticle(articleRepository.findArticleById(articleid),
warehouseEntryRepository.getArticleStock(articleid).orElse(0));
model.addAttribute("ArticleID", total);
return "intern/listedArticles/id";
}
@PostMapping("/{id}/saveChanges")
public RedirectView saveChanges(
@PathVariable int id,
@RequestParam("title") String title,
@RequestParam("description") String description,
@RequestParam("units-per-slot") String warehouseUnitsPerSlot,
@RequestParam("price_netto") String pricenetto,
@RequestParam("reorderMaxPrice") String reorderMaxPrice,
@RequestParam("autobuy") Boolean shouldReorder,
@RequestParam("categories") String categories) {
Article oldArticle = articleRepository.findArticleById(id);
// TODO img
String[] separatedCategories = categories.split("\n");
oldArticle.categories.clear();
// loop through all categories strings and create a new category if a new one; also adds the categorys to the article
for (String category : separatedCategories) {
oldArticle.categories.add(categoryRepository.findCategoryByName(category.trim())
.orElseGet(() -> new Category(category.trim())));
}
oldArticle.shouldReorder = shouldReorder;
oldArticle.reorderMaxPrice = (int) (Float.parseFloat(reorderMaxPrice) * 100);
oldArticle.shopPricePerUnitNetCent = (int) (Float.parseFloat(pricenetto) * 100);
oldArticle.warehouseUnitsPerSlot = Integer.parseInt(warehouseUnitsPerSlot);
oldArticle.title = title;
oldArticle.description = description;
articleRepository.save(oldArticle); // save updated article
return new RedirectView("../"); // return to overview page
}
public static class UImodelArticles {
public String imgPath;
public String title;
public String price;
public String price_netto;
public String categorie;
public int stock;
public long offer_id;
public long id;
void addListedArticle(Article article, int stock) {
this.imgPath = article.image.path;
this.title = article.title;
this.price_netto = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));
StringBuilder result = new StringBuilder();
for (Category temp : article.categories) {
result.append(temp.name + " ");
}
this.categorie = result.toString();
this.stock = stock;
this.offer_id = article.related.id;
this.id = article.id;
}
}
public static class UImodelArticle {
public String imgPath;
public String title;
public String price;
public String price_netto;
public String reorderMaxPrice;
public String categorie;
public int stock;
public long offer_id;
public long id;
public boolean shouldReorder;
public String warehouseUnitsPerSlot;
public String description;
public String getImgPath() {
return imgPath;
}
public void setImgPath(String imgPath) {
this.imgPath = imgPath;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getPrice_netto() {
return price_netto;
}
public void setPrice_netto(String price_netto) {
this.price_netto = price_netto;
}
public String getReorderMaxPrice() {
return reorderMaxPrice;
}
public void setReorderMaxPrice(String reorderMaxPrice) {
this.reorderMaxPrice = reorderMaxPrice;
}
public String getCategorie() {
return categorie;
}
public void setCategorie(String categorie) {
this.categorie = categorie;
}
public int getStock() {
return stock;
}
public void setStock(int stock) {
this.stock = stock;
}
public long getOffer_id() {
return offer_id;
}
public void setOffer_id(long offer_id) {
this.offer_id = offer_id;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public boolean isShouldReorder() {
return shouldReorder;
}
public void setShouldReorder(boolean shouldReorder) {
this.shouldReorder = shouldReorder;
}
public String getWarehouseUnitsPerSlot() {
return warehouseUnitsPerSlot;
}
public void setWarehouseUnitsPerSlot(String warehouseUnitsPerSlot) {
this.warehouseUnitsPerSlot = warehouseUnitsPerSlot;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
void addArticle(Article article, int stock) {
this.imgPath = article.image.path;
this.title = article.title;
this.price_netto = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));
StringBuilder result = new StringBuilder();
for (Category temp : article.categories) {
result.append(temp.name);
result.append("\n");
}
this.categorie = result.toString();
this.stock = stock;
this.offer_id = article.related.id;
this.id = article.id;
this.reorderMaxPrice = String.format("%.2f", ((float) article.reorderMaxPrice / 100));
this.shouldReorder = article.shouldReorder;
this.warehouseUnitsPerSlot = String.valueOf(article.warehouseUnitsPerSlot);
this.description = article.description;
}
}
}

View File

@ -35,7 +35,7 @@ public class Article {
@Basic(fetch = FetchType.LAZY)
public Image image;
@ManyToMany
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "article_categories_bindings")
public Set<Category> categories = new HashSet<>();
@ -46,4 +46,4 @@ public class Article {
public int getPriceGross() {
return shopPricePerUnitNetCent + getVat();
}
}
}

View File

@ -1,7 +1,5 @@
package org.hso.ecommerce.entities.shop;
import org.hso.ecommerce.entities.shop.Article;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.HashSet;
@ -22,4 +20,15 @@ public class Category {
@ManyToMany(mappedBy = "categories")
public Set<Article> articles = new HashSet<>();
public Category() {
}
public Category (String name) {
this.name = name;
}
}

View File

@ -11,17 +11,20 @@ import java.util.List;
@Repository
public interface ArticleRepository extends JpaRepository<Article, Long> {
@Query("SELECT a FROM Article a WHERE a.id = :articleId")
Article findArticleById(@Param("articleId") long articleId);
@Query("SELECT a FROM Article a WHERE a.id = :articleId")
Article findArticleById(@Param("articleId") long articleId);
@Query("SELECT a FROM Article a")
List<Article> findAll();
@Query("SELECT a FROM Article a JOIN a.related ao WHERE ao.shouldBeAdvertised = true")
List<Article> getAdvertisedArticles();
@Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC")
List<Article> getOrderedArticles();
@Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a WHERE c.id = :customerId ORDER BY co.id DESC")
List<Article> getOrderedArticles(long customerId);
}

View File

@ -0,0 +1,17 @@
package org.hso.ecommerce.repos.shop;
import org.hso.ecommerce.entities.shop.Category;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface CategoryRepository extends JpaRepository<Category, Long> {
@Query("SELECT a FROM Category a WHERE a.name = :name")
Optional<Category> findCategoryByName(@Param("name") String name);
}

View File

@ -6,12 +6,17 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface WarehouseBookingPositionSlotEntryRepository extends JpaRepository<WarehouseBookingPositionSlotEntry, Long> {
@Query(value = "Select e.id, e.article_id, e.new_sum_slot, e.slot_id from warehouse_booking_position_entries as e, warehouse_slots as s where e.slot_id = s.id AND e.article_id = :article GROUP BY s.slot_num HAVING max(e.id)", nativeQuery = true)
List<WarehouseBookingPositionSlotEntry> getByArticle(long article);
@Query(value = "SELECT SUM(w.new_sum_articles) FROM warehouse_booking_position_entries as w WHERE w.article_id = :articleid", nativeQuery = true)
Optional<Integer> getArticleStock(long articleid);
}

View File

@ -13,11 +13,7 @@
<ul>
<li><a th:href="@{/intern/}">Dashboard</a>
</li>
<li><a th:href="@{/intern/listedArticles/}">Gelistete Artikel</a>
<ul>
<li><a th:href="@{/intern/articles/}">Händlerangebote</a>
</li>
</ul>
<li><a th:href="@{/intern/articles/}">Gelistete Artikel</a>
</li>
<li><a th:href="@{/intern/accounting/}">Alle Buchungen</a>
<ul>
@ -38,7 +34,7 @@
<li><a th:href="@{/intern/suppliers/}">Lieferanten</a>
<ul>
<li><a th:href="@{/intern/supplierOrders/}">Bestellungen</a></li>
<li><a th:href="@{/intern/articles/}">&gt; Händlerangebote</a></li>
<li><a th:href="@{/intern/suppliers/articles/}">&gt; Händlerangebote</a></li>
</ul>
</li>

View File

@ -5,7 +5,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Gelistete Artikel</title>
<title>Bearbeiten: Artikel</title>
<script th:src="@{/js/filterTable.js}"></script>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
@ -15,7 +15,7 @@
<div class="sidebar-layout content-width">
<nav></nav>
<div>
<h1>Gelisteter Artikel 8450</h1>
<h1>Artikel bearbeiten</h1>
<script th:src="@{/js/back.js}"></script>
<div class="back" data-group="intern" data-insert="true"></div>
@ -24,16 +24,19 @@
<main class="sidebar-layout content-width">
<nav th:replace="fragments/intern :: sidebar"></nav>
<div class="content-width">
<h2>Gelisteter Artikel 8450</h2>
<form class="detailgrid">
<h2>Gelisteter Artikel ID <span th:text="${ArticleID.id}"></span></h2>
<form class="detailgrid" action="#" th:action="@{/intern/articles/{id}/saveChanges(id = ${ArticleID.id})}" th:object="${ArticleID}" method="POST" enctype="multipart/form-data">
<p class="m">
<label for="title">Titel</label>
<input class=" full-width" type="text" name="title" value="Kamera"/>
<input class=" full-width" type="text" name="title" th:value="${ArticleID.title}"/>
</p>
<p class="s">
<label for="ref-article">Refernzierter Artikel</label>
<input class="" type="text" name="ref-article" value="8405" disabled/>
<td><a th:href="@{/intern/articles/#q=%2044048}">Details</a></td>
<input class="" type="text" name="ref-article" th:value="${ArticleID.offer_id}" disabled/>
<td><a th:href="@{/intern/suppliers/articles/{id}(id = ${ArticleID.offer_id})}">Details</a></td>
</p>
<div class="spacer"></div>
<div class="m">
@ -42,26 +45,26 @@
<input class="full-width" type="file" name="img"/>
</p>
<p>
<img th:src="@{/img/product-1.jpg}" class="m"/>
<img th:src="@{/shop/articles/{id}/image.jpg(id=${ArticleID.id})}" class="m"/>
</p>
</div>
<div class="s">
<p>
<label for="price">Preis (Netto)</label>
<input class="" type="number" step="0.01" name="price" value="84.45"/>&nbsp;EUR <br/>
<input class="" type="number" step="0.01" name="price_netto" th:value="${ArticleID.price_netto}"/>&nbsp;EUR <br/>
(19% Mwst.)
<!-- Info von article ref--> <br/>
= 105.98&nbsp;EUR Brutto
= <span th:text="${ArticleID.price}"></span>&nbsp;EUR Brutto
</p>
<p>
<label for="max-price-buy">Maximaler Einkaufspreis (Netto)</label>
<input class="" type="number" step="0.01" name="price" value="80.98"/>&nbsp;EUR
<input class="" type="number" step="0.01" name="reorderMaxPrice" th:value="${ArticleID.reorderMaxPrice}"/>&nbsp;EUR
</p>
<div>
<fieldset>
<input type="radio" name="autobuy" value="true" id="autobuy-yes" checked required>
<input type="radio" name="autobuy" value="true" id="autobuy-yes" th:checked="${ArticleID.shouldReorder}" required>
<label for="autobuy-yes"> Automatisch nachbestellen.</label> <br/>
<input type="radio" name="autobuy" value="false" id="autobuy-no" required>
<input type="radio" name="autobuy" value="false" id="autobuy-no" th:checked="${!ArticleID.shouldReorder}" required>
<label for="autobuy-no"> Nicht mehr nachkaufen.</label> <br/>
</fieldset>
</div>
@ -72,19 +75,18 @@
<p>
Bitte jede Kategorien in eine eigene Zeile
</p>
<textarea name="tags" class="full-width" rows="6">
Überwachung
Elektronik
<textarea name="categories" class="full-width" rows="6"th:inline="text">[[${ArticleID.categorie}]]
</textarea>
</div>
<div class="s">
<p>
<label for="price">Einheiten pro Lagerplatz</label>
<input class="" type="number" name="units-per-slot" value="20"/>
<input class="" type="number" name="units-per-slot" th:value="${ArticleID.warehouseUnitsPerSlot}"/>
</p>
<p>
<b>Lagerbestand: 12</b>
<b>Lagerbestand: <span th:text="${ArticleID.stock}"></span></b>
</p>
<p>
Der Wert wird nur für zukünftige Lagerbuchungen verwendet.
@ -99,16 +101,13 @@ Elektronik
<p class="l">
<label for="description">Beschreibung</label>
<textarea name="description" class="full-width" rows="15">
Eine TOLLE Kamera
Jaja du denkst jetzt bestimmt: "Bei dem Preis kann sie gar nich sooo TOLL sein".
Aber glaub mir, sie is echt echt TOLL!
Indianerehrenwort!
<textarea name="description" class="full-width" rows="15" th:inline="text">[[${ArticleID.description}]]
</textarea>
</p>
<div class="l">
<button type="submit">Änderungen speichern</button>
<button type="reset">Zurücksetzen</button>
<button onclick="history.back()">Änderungen verwerfen</button>
</div>
</form>
</div>

View File

@ -24,81 +24,45 @@
<main class="sidebar-layout content-width">
<nav th:replace="fragments/intern :: sidebar"></nav>
<div class="content-width">
<h2>Artikel Hinzufügen</h2>
<p>
Weitere Artikel können über Artikelübersicht gelistet werden.
<a class="button smaller" th:href="@{/intern/articles/}"> Jetzt Hinzufügen </a>
Weitere Artikel können über Artikelübersicht der Lieferanten hinzugefügt werden.
<a class="button smaller" th:href="@{/intern/suppliers/articles}"> Jetzt Hinzufügen </a>
</p>
<p>
<table id="main-table">
<tr>
<th colspan="8">
<th colspan="9">
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
data-target-id="main-table"></input>
</th>
</tr>
<thead>
<tr>
<th>Bild</th>
<th>Name</th>
<th>Preis</th>
<th>(Netto)</th>
<th>Kategorien</th>
<th>Lagerbestand (Aktiv)</th>
<th>Artikel</th>
<th>Id (bearbeiten)</th>
</tr>
<tr>
<td><img th:src="@{/img/product-1.jpg}" class="s"/></td>
<td>Kamera</td>
<td>100,50&nbsp;EUR</td>
<td> (84.45&nbsp;EUR)</td>
<td>Úberwachung, Elektronik</td>
<td>301 <span class="checked"></span></td>
<td><a th:href="@{/intern/articles/#q=%2044048}">5051</a></td>
<td><a th:href="@{/intern/listedArticles/45015}">890</a></td>
</tr>
<tr>
<td><img th:src="@{/img/product-2.jpg}" class="s"/></td>
<td>Earbuds</td>
<td>63,95&nbsp;EUR</td>
<td>(53,73&nbsp;EUR)</td>
<td>Kopfhörer, Elektronik</td>
<td>12 <span class="checked"></span></td>
<td><a th:href="@{/intern/articles/#q=%2044048}">840</a></td>
<td><a th:href="@{/intern/listedArticles/45015}">13850</a></td>
</tr>
<tr>
<td><img th:src="@{/img/product-3.jpg}" class="s"/></td>
<td>USB-Magic Light</td>
<td>11,90&nbsp;EUR</td>
<td> (10,00&nbsp;EUR)</td>
<td>Sonstiges, Elektronik</td>
<td>3<span class="unchecked"></span></td>
<td><a th:href="@{/intern/articles/#q=%2044048}">8401</a></td>
<td><a th:href="@{/intern/listedArticles/45015}">5784</a></td>
</tr>
<tr>
<td><img th:src="@{/img/product-4.jpg}" class="s"/></td>
<td>3D Magic Stativ</td>
<td>15,99&nbsp;EUR</td>
<td> (13.44&nbsp;EUR)</td>
<td>Úberwachung, Elektronik</td>
<td>4<span class="checked"></span></td>
<td><a th:href="@{/intern/articles/#q=%2044048}">2135</a></td>
<td><a th:href="@{/intern/listedArticles/45015}">4564</a></td>
</tr>
<tr>
<td><img th:src="@{/img/product-5.jpg}" class="s"/></td>
<td>Ersatzfernbedinung</td>
<td>7,95&nbsp;EUR</td>
<td> (6.68&nbsp;EUR)</td>
<td>Úberwachung, Elektronik</td>
<td>0<span class="checked"></span></td>
<td><a th:href="@{/intern/articles/#q=%2044048}">4565</a></td>
<td><a th:href="@{/intern/listedArticles/45015}">4566</a></td>
<th>Lagerbestand</th>
<th>Angebots ID</th>
<th>Artikel ID</th>
<th>Aktion</th>
</tr>
</thead>
<tbody>
<tr th:each="article : ${ListedArticles}">
<td><img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}" class="s"/></td>
<td><span th:text="${article.title}"></span></td>
<td><span th:text="${article.price}"></span></td>
<td><span th:text="${article.price_netto}"></span></td>
<td><span th:text="${article.categorie}"></span></td>
<td><span th:text="${article.stock}"></span></td>
<td><a th:href="@{/intern/suppliers/articles/{id}(id = ${article.offer_id})}" th:text="${article.offer_id}"></a></td>
<td><a th:href="@{/intern/articles/{id}(id = ${article.id})}" th:text="${article.id}"></a></td>
<td><form th:action="@{/intern/articles/{id}(id = ${article.id})}"><input type="submit" value="Bearbeiten" /></form></td>
</tr>
</tbody>
</table>
<p>
</div>