StatisticsController for SalesVolume and SalesRevenue, fix OrderController
This commit is contained in:
Binary file not shown.
@@ -41,4 +41,10 @@ public class ControllerPathConfig {
|
||||
//ReviewController
|
||||
public static final String REVIEW_BASE = "/review";
|
||||
public static final String REVIEW_GET_ALL = REVIEW_BASE + "/all";
|
||||
|
||||
//StatisticsController
|
||||
private static final String STATISTICS_BASE = "/statistics";
|
||||
public static final String STATISTICS_VOLUME = STATISTICS_BASE + "/volume";
|
||||
public static final String STATISTICS_REVENUE = STATISTICS_BASE + "/revenue";
|
||||
|
||||
}
|
||||
@@ -13,4 +13,5 @@ public class ParameterConfig {
|
||||
public static final String PARAM_IMAGE = "image";
|
||||
public static final String PARAM_STATUS = "status";
|
||||
public static final String PARAM_STANDARD = "standard";
|
||||
public static final String PARAM_SESSION = "session";
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ public class OrderController {
|
||||
log.warn("[{}] failed Validation, sending bad request", request.getRequestURI());
|
||||
return ResponseEntity.badRequest().body(false);
|
||||
}
|
||||
|
||||
order.setId(null);
|
||||
order.getOrderItems().forEach(orderItem -> orderItem.setId(null));
|
||||
Order saved = orderService.save(order);
|
||||
return ResponseEntity.ok(saved != null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package de.htwsaar.webshop.controller;
|
||||
|
||||
import de.htwsaar.webshop.model.MonthlyCatModel;
|
||||
import de.htwsaar.webshop.service.SessionService;
|
||||
import de.htwsaar.webshop.service.StatisticsService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static de.htwsaar.webshop.config.ControllerPathConfig.STATISTICS_REVENUE;
|
||||
import static de.htwsaar.webshop.config.ControllerPathConfig.STATISTICS_VOLUME;
|
||||
import static de.htwsaar.webshop.config.ParameterConfig.PARAM_EMAIL;
|
||||
import static de.htwsaar.webshop.config.ParameterConfig.PARAM_SESSION;
|
||||
import static de.htwsaar.webshop.util.LoggerUtil.logRequest;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class StatisticsController {
|
||||
|
||||
private final StatisticsService statisticsService;
|
||||
private final SessionService sessionService;
|
||||
|
||||
public StatisticsController(StatisticsService statisticsService, SessionService sessionService) {
|
||||
this.statisticsService = statisticsService;
|
||||
this.sessionService = sessionService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = STATISTICS_VOLUME, method = RequestMethod.GET, produces = "application/json")
|
||||
public ResponseEntity<MonthlyCatModel<Integer>> getMonthlySalesVolume(HttpServletRequest request,
|
||||
@RequestParam(value = PARAM_SESSION) UUID session,
|
||||
@RequestParam(value = PARAM_EMAIL) String email) {
|
||||
logRequest(request);
|
||||
if (!sessionService.isAdmin(session, email)) {
|
||||
log.warn("Invalid session requesting Admin {}", session);
|
||||
return ResponseEntity.status(403).build();
|
||||
}
|
||||
return ResponseEntity.ok(statisticsService.getSalesVolume());
|
||||
}
|
||||
|
||||
@RequestMapping(value = STATISTICS_REVENUE, method = RequestMethod.GET, produces = "application/json")
|
||||
public ResponseEntity<MonthlyCatModel<Integer>> getMonthlyRevenue(HttpServletRequest request,
|
||||
@RequestParam(value = PARAM_SESSION) UUID token,
|
||||
@RequestParam(value = PARAM_EMAIL) String email) {
|
||||
logRequest(request);
|
||||
if (!sessionService.isAdmin(token, email)) {
|
||||
log.warn("Invalid session requesting Admin {}", token);
|
||||
return ResponseEntity.status(403).build();
|
||||
}
|
||||
return ResponseEntity.ok(statisticsService.getSalesRevenue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package de.htwsaar.webshop.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
public class MonthlyCatModel<T extends Number> {
|
||||
Map<Long, Map<String, T>> monthCategoryMap;
|
||||
|
||||
}
|
||||
@@ -9,4 +9,6 @@ import java.util.List;
|
||||
@Repository
|
||||
public interface OrderRepository extends JpaRepository<Order, Long> {
|
||||
List<Order> getOrdersByCustomer_Id(Long customerId);
|
||||
|
||||
List<Order> getOrdersByTimeBetween(Long timeAfter, Long timeBefore);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.hibernate.type.NumericBooleanConverter;
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
@Entity
|
||||
@Table(name = "FarmImages")
|
||||
@Table(name = "Farm_Images")
|
||||
public class FarmImage {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
|
||||
@@ -31,10 +31,9 @@ public class Order {
|
||||
@Column(name = "status", nullable = false)
|
||||
private OrderStatus status;
|
||||
|
||||
@OneToMany(mappedBy = "order", orphanRemoval = true, fetch = FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = OrderItem.class)
|
||||
@OneToMany(mappedBy = "order", orphanRemoval = true, fetch = FetchType.EAGER, cascade = CascadeType.ALL, targetEntity = OrderItem.class)
|
||||
private List<OrderItem> orderItems;
|
||||
|
||||
|
||||
public OrderModel toModel() {
|
||||
return new OrderModel(id, customer.getId(), time, status, orderItems.stream().map(OrderItem::toModel).toList());
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.hibernate.annotations.OnDelete;
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "OrderItems")
|
||||
@Table(name = "Order_Items")
|
||||
public class OrderItem {
|
||||
|
||||
@Id
|
||||
@@ -25,8 +25,8 @@ public class OrderItem {
|
||||
@Min(value = 1, message = "Amount must be at least 1")
|
||||
private Integer amount;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@MapsId("orderId")
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL, targetEntity = Order.class)
|
||||
@MapsId("order_id")
|
||||
@JoinColumn(name = "order_id", referencedColumnName = "id", nullable = false)
|
||||
@OnDelete(action = org.hibernate.annotations.OnDeleteAction.CASCADE)
|
||||
private Order order;
|
||||
|
||||
@@ -4,6 +4,7 @@ import de.htwsaar.webshop.model.OrderModel;
|
||||
import de.htwsaar.webshop.repository.entities.Order;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface OrderService {
|
||||
Order save(Order order);
|
||||
@@ -15,4 +16,6 @@ public interface OrderService {
|
||||
Order getOrderById(Long orderId);
|
||||
|
||||
List<Order> getAllOrders(Long customerId);
|
||||
|
||||
Map<Long, List<Order>> getTimeSortedOrders(long fromMilli, long months);
|
||||
}
|
||||
|
||||
@@ -18,5 +18,5 @@ public interface SessionService {
|
||||
|
||||
boolean isValid(UUID token, String email);
|
||||
|
||||
boolean isAdmin(Session session, String email);
|
||||
boolean isAdmin(UUID token, String email);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.htwsaar.webshop.service;
|
||||
|
||||
import de.htwsaar.webshop.model.MonthlyCatModel;
|
||||
|
||||
public interface StatisticsService {
|
||||
MonthlyCatModel<Integer> getSalesVolume();
|
||||
|
||||
MonthlyCatModel<Integer> getSalesRevenue();
|
||||
|
||||
}
|
||||
@@ -8,11 +8,14 @@ import de.htwsaar.webshop.repository.entities.OrderItem;
|
||||
import de.htwsaar.webshop.service.ArticleService;
|
||||
import de.htwsaar.webshop.service.CustomerService;
|
||||
import de.htwsaar.webshop.service.OrderService;
|
||||
import de.htwsaar.webshop.util.TimeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@@ -69,4 +72,19 @@ public class OrderServiceImpl implements OrderService {
|
||||
public List<Order> getAllOrders(Long customerId) {
|
||||
return orderRepository.getOrdersByCustomer_Id(customerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, List<Order>> getTimeSortedOrders(long fromMilli, long months) {
|
||||
Map<Long, List<Order>> orders = new HashMap<>();
|
||||
long lower = fromMilli;
|
||||
long upper;
|
||||
while (months > 0) {
|
||||
upper = fromMilli + TimeUtil.monthLength(fromMilli);
|
||||
log.info("Getting Orders from {} to {}", lower, upper);
|
||||
orders.put(fromMilli, orderRepository.getOrdersByTimeBetween(lower, upper));
|
||||
lower = upper;
|
||||
months--;
|
||||
}
|
||||
return orders;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,11 +72,11 @@ public class SessionServiceImpl implements SessionService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdmin(Session session, String email) {
|
||||
if(session == null || email == null) {
|
||||
public boolean isAdmin(UUID token, String email) {
|
||||
if(token == null || email == null) {
|
||||
return false;
|
||||
}
|
||||
if(!isValid(session, email)) {
|
||||
if(!isValid(token, email)) {
|
||||
log.warn("Invalid Session with email {} trying to access Admin Services", email);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.htwsaar.webshop.service.impl;
|
||||
|
||||
import de.htwsaar.webshop.model.MonthlyCatModel;
|
||||
import de.htwsaar.webshop.repository.entities.Order;
|
||||
import de.htwsaar.webshop.repository.entities.OrderItem;
|
||||
import de.htwsaar.webshop.service.OrderService;
|
||||
import de.htwsaar.webshop.service.StatisticsService;
|
||||
import de.htwsaar.webshop.util.TimeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class StatisticsServiceImpl implements StatisticsService {
|
||||
private final OrderService orderService;
|
||||
|
||||
@Autowired
|
||||
public StatisticsServiceImpl(OrderService orderService) {
|
||||
this.orderService = orderService;
|
||||
}
|
||||
|
||||
//don't ask pls
|
||||
//returns Map<unix milli timestamp, Map<Category, T>>
|
||||
private <T extends Number> MonthlyCatModel<T> getMonthCategoryMap(Function<OrderItem, T> mappingFunction,
|
||||
BinaryOperator<T> reduceFunction) {
|
||||
return new MonthlyCatModel<>(
|
||||
orderService.getTimeSortedOrders(TimeUtil.nowMonthsAgo(12), 12).entrySet().stream()
|
||||
.map(entry -> Map.entry(entry.getKey(),
|
||||
entry.getValue().stream()
|
||||
.map(Order::getOrderItems)
|
||||
.reduce(new ArrayList<>(), (l, r) -> {
|
||||
l.addAll(r);
|
||||
return l;
|
||||
})
|
||||
.stream()
|
||||
.map(orderItem -> Map.entry(orderItem.getArticle().getCategory(), mappingFunction.apply(orderItem)))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, reduceFunction))
|
||||
))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonthlyCatModel<Integer> getSalesVolume() {
|
||||
return getMonthCategoryMap(OrderItem::getAmount, Integer::sum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonthlyCatModel<Integer> getSalesRevenue() {
|
||||
return getMonthCategoryMap(item -> item.getArticle().getPrice100(), Integer::sum);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
package de.htwsaar.webshop.util;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
/**
|
||||
* Helper Class for Unix-Millis related Things
|
||||
*/
|
||||
@@ -41,13 +45,11 @@ public class TimeUtil {
|
||||
return System.currentTimeMillis() + (days * MILLIS_TO_DAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the Unix-Millis are valid
|
||||
*
|
||||
* @param time the Millis to Check
|
||||
* @return whether the Time <b>can</b> be valid
|
||||
*/
|
||||
public static boolean isValidTime(long time) {
|
||||
return time >= VALID_MIN_MILLIS_TIMESTAMP;
|
||||
public static long nowMonthsAgo(long months) {
|
||||
return LocalDateTime.now().minusMonths(months).atZone(ZoneId.systemDefault()).toEpochSecond();
|
||||
}
|
||||
|
||||
public static long monthLength(long epoch) {
|
||||
return LocalDateTime.ofEpochSecond(epoch, 0, ZoneOffset.UTC).getMonth().length(false) * MILLIS_TO_DAY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS Images
|
||||
FOREIGN KEY (article_id) REFERENCES Articles (id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS FarmImages
|
||||
CREATE TABLE IF NOT EXISTS Farm_Images
|
||||
(
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
article_id INTEGER NOT NULL,
|
||||
@@ -82,7 +82,7 @@ CREATE TABLE IF NOT EXISTS Orders
|
||||
ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS OrderItems
|
||||
CREATE TABLE IF NOT EXISTS Order_Items
|
||||
(
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
order_id INTEGER NOT NULL,
|
||||
|
||||
Reference in New Issue
Block a user