Merge branch 'master' into feature/offeredArticle

This commit is contained in:
Jannik 2020-05-21 20:23:47 +02:00
commit 525a5f7eb1
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
12 changed files with 109 additions and 96 deletions

0
prototype/gradlew vendored Executable file → Normal file
View File

View File

@ -85,11 +85,6 @@ public class RequestController {
return "redirect:/"; return "redirect:/";
} }
@GetMapping("/shop/search")
public String shopSearch() {
return "shop/search";
}
@GetMapping("/intern/") @GetMapping("/intern/")
public String intern() { public String intern() {
return "intern/index"; return "intern/index";

View File

@ -5,6 +5,7 @@ import org.hso.ecommerce.action.shop.GetRandomArticlesAction;
import org.hso.ecommerce.entities.shop.Article; import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.shop.ShoppingCart; import org.hso.ecommerce.entities.shop.ShoppingCart;
import org.hso.ecommerce.repos.shop.ArticleRepository; import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.shop.CategoryRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository; import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -30,12 +31,17 @@ public class ShopArticleController {
@Autowired @Autowired
private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null; private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
@Autowired
private final CategoryRepository categoryRepository = null;
@GetMapping("/{id}") @GetMapping("/{id}")
public String shopArticlesById(Model model, public String shopArticlesById(Model model,
@PathVariable("id") Long id, @PathVariable("id") Long id,
HttpServletRequest request, HttpServletRequest request,
HttpServletResponse response HttpServletResponse response
) { ) {
model.addAttribute("categories", categoryRepository.getCategories()); //for sidebar
Article article = articleRepository.findArticleById(id); Article article = articleRepository.findArticleById(id);
if (article == null) { if (article == null) {
@ -45,13 +51,13 @@ public class ShopArticleController {
} }
model.addAttribute("article", article); model.addAttribute("article", article);
if (warehouseBookingPositionSlotEntryRepository.getByArticle(id).get(0).newSumSlot > 0) { if (warehouseBookingPositionSlotEntryRepository.getByArticle(id).get(0).newSumSlot > 0) { //check if in Stock
model.addAttribute("inStock", true); model.addAttribute("inStock", true);
} else { } else {
model.addAttribute("inStock", false); model.addAttribute("inStock", false);
} }
List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(3, articleRepository.getAdvertisedArticles()); List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(3, articleRepository.getAdvertisedArticles()); //get 3 advertised Articles
model.addAttribute("commercialArticles", commercialArticles); model.addAttribute("commercialArticles", commercialArticles);
return "shop/articles/id"; return "shop/articles/id";
@ -98,5 +104,4 @@ public class ShopArticleController {
response.setContentType(MediaType.IMAGE_JPEG_VALUE); response.setContentType(MediaType.IMAGE_JPEG_VALUE);
IOUtils.copy(in, response.getOutputStream()); IOUtils.copy(in, response.getOutputStream());
} }
} }

View File

@ -3,6 +3,7 @@ package org.hso.ecommerce.controller.shop;
import org.hso.ecommerce.action.shop.GetRandomArticlesAction; import org.hso.ecommerce.action.shop.GetRandomArticlesAction;
import org.hso.ecommerce.entities.shop.Article; import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.repos.shop.ArticleRepository; import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -19,6 +20,9 @@ public class ShopIndexController {
@Autowired @Autowired
private final ArticleRepository articleRepository = null; private final ArticleRepository articleRepository = null;
@Autowired
private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
@GetMapping("/") @GetMapping("/")
public String home() { public String home() {
return "redirect:/shop/"; return "redirect:/shop/";
@ -27,18 +31,18 @@ public class ShopIndexController {
@GetMapping("/shop/") @GetMapping("/shop/")
public String shop(Model model, HttpSession session) { public String shop(Model model, HttpSession session) {
List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(8, articleRepository.getAdvertisedArticles()); List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(8, articleRepository.getAdvertisedArticles()); //get random advertised Articles
model.addAttribute("commercialArticles", commercialArticles); model.addAttribute("commercialArticles", commercialArticles);
boolean isLoggedIn = false; boolean isLoggedIn = false;
boolean hasOrders = false; boolean hasOrders = false;
if (session != null && session.getAttribute("userId") != null) { if (session != null && session.getAttribute("userId") != null) { //check if logged in
long userId = (long) session.getAttribute("userId"); long userId = (long) session.getAttribute("userId");
isLoggedIn = true; isLoggedIn = true;
List<Article> suggestedArticles = articleRepository.getOrderedArticles(userId); List<Article> suggestedArticles = articleRepository.getOrderedArticles(userId);
suggestedArticles = suggestedArticles.size() > 3 ? suggestedArticles.subList(0, 4) : suggestedArticles; //only latest 4 articles suggestedArticles = suggestedArticles.size() > 3 ? suggestedArticles.subList(0, 4) : suggestedArticles; //only latest 4 ordered articles
if (suggestedArticles.size() > 0) { if (suggestedArticles.size() > 0) {
model.addAttribute("suggestedArticles", suggestedArticles); model.addAttribute("suggestedArticles", suggestedArticles);
hasOrders = true; hasOrders = true;
@ -65,5 +69,4 @@ public class ShopIndexController {
public String privacy() { public String privacy() {
return "privacy"; return "privacy";
} }
} }

View File

@ -1,8 +1,48 @@
package org.hso.ecommerce.controller.shop; package org.hso.ecommerce.controller.shop;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.shop.CategoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Controller @Controller
//@RequestMapping("...") @RequestMapping("/shop/search")
public class ShopSearchController { public class ShopSearchController {
}
@Autowired
private final ArticleRepository articleRepository = null;
@Autowired
private final CategoryRepository categoryRepository = null;
@GetMapping("")
public String searchArticles(@RequestParam(required = false, value = "term") String term,
@RequestParam(required = false, value = "category") String category,
Model model,
HttpServletRequest request,
HttpServletResponse response
) {
model.addAttribute("categories", categoryRepository.getCategories()); //for sidebar
if (term != null) { //if search by Term
List<Article> articles = articleRepository.getArticlesByTerm(term); //search by Term
model.addAttribute("articles", articles);
} else if (category != null) { //if search by Category
List<Article> articles = articleRepository.getArticlesByCategory(category); //search by Category
model.addAttribute("articles", articles);
} else {
request.setAttribute("error", "Es wurden keine Suchparameter angegeben.");
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return "error/404";
}
return "/shop/search";
}
}

View File

@ -18,7 +18,7 @@ public interface ArticleRepository extends JpaRepository<Article, Long> {
@Query("SELECT a FROM Article a") @Query("SELECT a FROM Article a")
List<Article> findAll(); List<Article> findAll();
@Query("SELECT a FROM Article a JOIN a.related ao WHERE ao.shouldBeAdvertised = true") @Query(value = "Select a.* from articles as a, article_offers as ao, warehouse_booking_position_entries as wbpe where a.related_id = ao.id and wbpe.article_id = a.id and ao.should_be_advertised = true group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
List<Article> getAdvertisedArticles(); 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") @Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC")
@ -30,4 +30,9 @@ public interface ArticleRepository extends JpaRepository<Article, Long> {
@Query(value = "SELECT a.id FROM articles a WHERE a.related_id = :relatedId", nativeQuery = true) @Query(value = "SELECT a.id FROM articles a WHERE a.related_id = :relatedId", nativeQuery = true)
Optional<Integer> findArticleIDByRelatedID(@Param("relatedId") long relatedId); Optional<Integer> findArticleIDByRelatedID(@Param("relatedId") long relatedId);
} @Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.title LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
List<Article> getArticlesByTerm(String term);
@Query(value = "Select a.* from articles as a, categories as c, article_categories_bindings as acb, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and acb.articles_id = a.id and acb.categories_id = c.id and c.name = :category group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
List<Article> getArticlesByCategory(String category);
}

View File

@ -6,6 +6,7 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional; import java.util.Optional;
@Repository @Repository
@ -14,4 +15,6 @@ public interface CategoryRepository extends JpaRepository<Category, Long> {
@Query("SELECT a FROM Category a WHERE a.name = :name") @Query("SELECT a FROM Category a WHERE a.name = :name")
Optional<Category> findCategoryByName(@Param("name") String name); Optional<Category> findCategoryByName(@Param("name") String name);
} @Query("SELECT c FROM Category c")
List<Category> getCategories();
}

View File

@ -11,7 +11,7 @@
<div class='content-width bar-flex'> <div class='content-width bar-flex'>
<a class="button no-padding" href="/"><img class="logo" th:src="@{/img/ecom-logo-base.svg}"></a> <a class="button no-padding" href="/"><img class="logo" th:src="@{/img/ecom-logo-base.svg}"></a>
<form class='spacer input-icon secondary' th:action="@{/shop/search}" method="GET"> <form class='spacer input-icon secondary' th:action="@{/shop/search}" method="GET">
<input type="text" placeholder="Nach Produkten suchen..."/> <input type="text" name="term" placeholder="Nach Produkten suchen..."/>
<button>Finden</button> <button>Finden</button>
</form> </form>
<a th:unless="${user}" class="button" th:href="@{/login}">Login</a> <a th:unless="${user}" class="button" th:href="@{/login}">Login</a>
@ -38,7 +38,6 @@
function toggle(id) { function toggle(id) {
document.getElementById(id).classList.toggle("invisible"); document.getElementById(id).classList.toggle("invisible");
} }
</script> </script>
<a class="secondary button error" href="javascript:void(0)" onclick="toggle('error-msg');">X</a> <a class="secondary button error" href="javascript:void(0)" onclick="toggle('error-msg');">X</a>
</div> </div>
@ -54,7 +53,6 @@
function toggle(id) { function toggle(id) {
document.getElementById(id).classList.toggle("invisible"); document.getElementById(id).classList.toggle("invisible");
} }
</script> </script>
<a class="secondary button info" href="javascript:void(0)" onclick="toggle('info-msg');">X</a> <a class="secondary button info" href="javascript:void(0)" onclick="toggle('info-msg');">X</a>
</div> </div>
@ -62,5 +60,4 @@
</div> </div>
</nav> </nav>
</body> </body>
</html> </html>

View File

@ -7,15 +7,10 @@
</head> </head>
<body> <body>
<nav th:fragment="sidebar"> <nav th:fragment="sidebar (categories)">
<h1>Kategorien</h1> <h1>Kategorien</h1>
<ul class="secondary"> <ul class="secondary">
<li><a href="/shop/search">Aufnahmegeräte</a></li> <li th:each="category: ${categories}"><a th:href="@{/shop/search(category=${category.name})}" th:text="${category.name}"></a></li>
<li><a href="/shop/search">Computer</a></li>
<li><a href="/shop/search">Fernseher</a></li>
<li><a href="/shop/search">Handys</a></li>
<li><a href="/shop/search">Unterhaltungselektronik</a></li>
<li><a href="/shop/search">Sonstiges</a></li>
</ul> </ul>
</nav> </nav>
</body> </body>

View File

@ -14,7 +14,7 @@
<nav th:replace="fragments/header :: header">Header</nav> <nav th:replace="fragments/header :: header">Header</nav>
<main class=" content-width"> <main class=" content-width">
<div class="sidebar-layout" style="min-height: 75vh;"> <div class="sidebar-layout" style="min-height: 75vh;">
<nav th:replace="fragments/shop :: sidebar"></nav> <nav th:replace="fragments/shop :: sidebar(categories=${categories})"></nav>
<div class="content-width"> <div class="content-width">
<div class="detailgrid"> <div class="detailgrid">
<div class="s"> <div class="s">
@ -23,7 +23,9 @@
<script th:src="@{/js/back.js}"></script> <script th:src="@{/js/back.js}"></script>
<div class="back" data-group="shop" data-insert="true"></div> <div class="back" data-group="shop" data-insert="true"></div>
<h2><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></h2> <h2><span
th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
</h2>
<p th:text="${article.description}"></p> <p th:text="${article.description}"></p>
</div> </div>
<div class="s"> <div class="s">
@ -32,7 +34,9 @@
<div class="s"></div> <div class="s"></div>
<form class="s" method="POST"> <form class="s" method="POST">
<div class="detailgrid m"> <div class="detailgrid m">
<h2><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></h2> <h2><span
th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
</h2>
<div> <div>
<label class="nolinebreak">Menge:</label> <label class="nolinebreak">Menge:</label>
<select name="quantity" size="1"> <select name="quantity" size="1">
@ -55,10 +59,13 @@
<div> <div>
<h1>Weitere Schnäppchen</h1> <h1>Weitere Schnäppchen</h1>
<div class='grid m base shadow'> <div class='grid m base shadow'>
<section th:each="article: ${commercialArticles}"><a th:href="@{/shop/articles/{id}(id = ${article.id})}" class="section"> <section th:each="article: ${commercialArticles}"><a
th:href="@{/shop/articles/{id}(id = ${article.id})}" class="section">
<img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/> <img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/>
<h2 th:text="${article.title}"></h2> <h2 th:text="${article.title}"></h2>
<p class='price'><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></p> <p class='price'><span
th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
</p>
<p th:text="${article.description}"></p> <p th:text="${article.description}"></p>
</a> </a>
</section> </section>

View File

@ -25,9 +25,11 @@
<a th:href="@{/shop/articles/{id}(id=${article.id})}" class="section"> <a th:href="@{/shop/articles/{id}(id=${article.id})}" class="section">
<img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/> <img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/>
<h2 th:text="${article.title}" /> <h2 th:text="${article.title}"/>
<p class='price'><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></p> <p class='price'><span
<p th:text="${article.description}" /> th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
</p>
<p th:text="${article.description}"/>
</a> </a>
</section> </section>
<section class="spacer"></section> <section class="spacer"></section>
@ -57,7 +59,7 @@
<!-- If User is logged in but hasn't ordered anything yet--> <!-- If User is logged in but hasn't ordered anything yet-->
<div th:if="${isLoggedIn == true and hasOrders == false}"> <div th:if="${isLoggedIn == true and hasOrders == false}">
<h1>Jetzt Shoppen und Empfehlungen erhalten!</h1> <h2>Jetzt Shoppen und Empfehlungen erhalten!</h2>
</div> </div>
<!-- If User is logged in and has ordered something before--> <!-- If User is logged in and has ordered something before-->
@ -67,9 +69,11 @@
<a th:href="@{/shop/articles/{id}(id=${article.id})}" class="section"> <a th:href="@{/shop/articles/{id}(id=${article.id})}" class="section">
<img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/> <img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/>
<h2 th:text="${article.title}" /> <h2 th:text="${article.title}"/>
<p class='price'><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></p> <p class='price'><span
<p th:text="${article.description}" /> th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
</p>
<p th:text="${article.description}"/>
</a> </a>
</section> </section>
</div> </div>

View File

@ -21,70 +21,29 @@
</div> </div>
</div> </div>
<main class="sidebar-layout content-width"> <main class="sidebar-layout content-width">
<nav th:replace="fragments/shop :: sidebar"></nav> <nav th:replace="fragments/shop :: sidebar(categories=${categories})"></nav>
<div class="content-width"> <div class="content-width">
<div class='grid m condensed'> <div class='grid m condensed' th:if="${articles.size() != 0}">
<section><a th:href="@{/shop/articles/1234}" class="section"> <section th:each="article: ${articles}">
<img th:src="@{/img/product-1.jpg}"> <a th:href="@{/shop/articles/{id}(id=${article.id})}" class="section">
<h2>Tolle Kamera</h2>
<p class='price'> 25.14&nbsp;EUR</p>
<p>
Eine TOLLE Kamera <br>
Jaja du denkst jetzt bestimmt: "Bei dem Preis kann sie gar nich sooo TOLL sein". <br>
Aber glaub mir, sie is echt echt TOLL! <br>
Indianerehrenwort!
</p>
</a>
</section>
<section><a th:href="@{/shop/articles/1234}" class="section"> <img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/>
<img th:src="@{/img/product-2.jpg}"> <h2 th:text="${article.title}"/>
<h2>Bluetooth Kopfhörer</h2> <p class='price'><span
<p class='price'> 10.14&nbsp;EUR</p> th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
<p> </p>
Sind halt Kopfhörer ohne Kabel, mehr gibts da nich zu sagen. <p th:text="${article.description}"/>
</p> </a>
</a>
</section> </section>
<section><a th:href="@{/shop/articles/1234}" class="section">
<img th:src="@{/img/product-3.jpg}">
<h2>???</h2>
<p class='price'> 25.14&nbsp;EUR</p>
<p>
Ich weiß selbst nich was das genau sein soll.<br>
Wenn dus willst kannst es gern haben, musst nur das Geld überweisen.
</p>
</a>
</section>
<section><a th:href="@{/shop/articles/1234}" class="section">
<img th:src="@{/img/product-4.jpg}">
<h2>Kamera Stativ.</h2>
<p class='price'> 25.14&nbsp;EUR</p>
<p>
Das Stativ der Zukunft! Jetzt kaufen und verwenden für
wackelfreie Bilder aus der Zukunft!.
</p>
</a>
</section>
<section><a th:href="@{/shop/articles/1234}" class="section">
<img th:src="@{/img/product-5.jpg}">
<h2>Bluetooth Ersatzfernbedinung</h2>
<p class='price'> 10.14&nbsp;EUR</p>
<p>
Kann alles und jeden ausknippsen.
</p>
</a>
</section>
<section class="spacer"></section> <section class="spacer"></section>
<section class="spacer"></section> <section class="spacer"></section>
<section class="spacer"></section> <section class="spacer"></section>
<section class="spacer"></section> <section class="spacer"></section>
</div> </div>
<div th:if="${articles.size() == 0}">
<h2>Keine Ergebnisse für diesen Suchterm gefunden!</h2>
</div>
</div> </div>
</main> </main>
<footer th:replace="fragments/footer :: footer"></footer> <footer th:replace="fragments/footer :: footer"></footer>