From 838498227c823e00054a016ccf4972ed298e53fa Mon Sep 17 00:00:00 2001 From: Tim <47184194+imgde@users.noreply.github.com> Date: Mon, 16 Jun 2025 00:29:25 +0200 Subject: [PATCH] add OrderStatus statistic, stock fullfilment dummy --- 00-backend/datasource/database.sqlite | Bin 27684864 -> 27684864 bytes .../webshop/config/ControllerPathConfig.java | 1 + .../controller/StatisticsController.java | 17 +++- .../webshop/service/StatisticsService.java | 5 + .../service/impl/StatisticsServiceImpl.java | 11 +++ .../src/helper/adminpanel/StatisticsInfo.tsx | 93 ++++++++++++++---- 01-frontend/src/helper/helper.css | 4 + 01-frontend/src/helper/query/Queries.tsx | 8 ++ 8 files changed, 119 insertions(+), 20 deletions(-) diff --git a/00-backend/datasource/database.sqlite b/00-backend/datasource/database.sqlite index c048ddf24492e2b1bb9bcff640d2df994d785cff..9aadb751128bdd529922351f889ea759a22ab576 100644 GIT binary patch delta 2173 zcmZA1cU0A79LMqdL+<5X#oq&N0TC5N5pfUPdv9@|xHs;txKLEw7hHgfI~zu#6l9v3 zS!RQVmK9cJMWq(5%ChzT^pEHC$LoE5&vSm~`<(Oq@g&{IES-eZV9T2p(#h#{L{GYP zV#0yZ0WOo}Fqh0dbJLtM$4pjk;Ft|2(%HQ@gRTalhu)6f8QsoeI;`* z&1w@+!DF%==8-8jMdrG>VlJEWCeLIuYrBc@^YFjrak<@YeONA+%g^t>EvMV9b1cir zmd>y|zHYb1Tb8fOm0aXaDe_wIK?(T62^aj}h6g243jQb!8wLRgL>ZJtIh02QR753I zMi7D#f+`3_RfM4$s-p(NQ4_WDi@Xt`VPUo%@8IGtnxkgDNie-lv6t5_J)UdWc4SG(bZ%LSr;R zQ#3va@jK>5_#3W3{6ih_|reQi}U?yf^Hs)Y1=3zb-U?CP^F_s_^ zOR)^gu>vcRgjHCLWURqjtV0UcV*@r~6E_ry# zVLuMwAP(U$j^HUA#nX5O&*C{8!}G|-3pkD(oWM!s;zhiKJmlkLoWd(OjWc)^XK@ba z@ft4RbzH<7coUcK7B1s$yn}b~9t!Y2KEQ|g2v=|wALA2T!>9NRpQ8}h@ddubSGa+% zaTDL*TYQHie2*XSBW~d~?%*f16wJj5^f6~EyTe#akpj6d-g{>DF>iVG|+ z6d$F8;;T3nm*S_m6^~LPihIT&bzlQX-VvN*yIqsjEaO^^|C(zS2Nxs5DXcRt_sE7LS zf&~L__@DuN(GZQ$7){U=&EN-r1fV$r(E>qeiB@QhV6;Ko3a7&!7!>4XCAyd@bJ?6U z=_bL%m@wmQ-LtM)XRJIc(MqTYK5g%11?Jp&m{rofQ=Ba~Bc!a*-*R^eb@vE!D@eU{ zKicI+H>KvfxnxpIo^dx(=C+A7;Z}{6RuO#Be$Mj#f6f2?l^fBa zrD@ey?P!M(v_}Voq9ei(j!x)|F6fGG=#C!fiC*Z9KIn^nh(Lb~z(5SbU_>GcLogJ> zFdWesfsu&8D2&D!jKw&N#{^8oBuvH>OhqiFAr8|q12YkiS(uGEn2ULsj|EtWMOcgk zEWuJN!*Z;^O02?atif8W!+LDMMr=YNHe(C6A_?1&jP2Ng6r^G&b|DSv*o_QiVh{FW z9~{U+HufV22XGLFkc&LzqX36-1cf+?V<l*e2K5{HE!Y?RN)rB#dmPxd;EYO@e_W=ZQQ{xs74L$;vRm* zZ}=U5;65JUPdvn5_#6M=Up&gJzG`zosin9oZi>57TdAYeRXh|=rJhn>@lq_sDBg;X z(m?T58Y+#H#!3^VsnSgGQ~Z?xrMVKQv`~VSmP#w7wGynfQQ9hYrJWL@v{yPPp-M+3 zObJ&yDV>!rN>`S*9#kRwyf#Rmy5*jj~o*r>s{tC>xbcN}{q^*`jP!l9X*qva(&- zp`<9O%1&jMlBT39yOj(jQ`w{JRrVUx_A5Ec0p*}_NXb?5lzgQ?IjkH}3YDYE VF{MZ;R*owr$_d*Aew59p_&@(awG;pV diff --git a/00-backend/src/main/java/de/htwsaar/webshop/config/ControllerPathConfig.java b/00-backend/src/main/java/de/htwsaar/webshop/config/ControllerPathConfig.java index 084eed2..cdc1f56 100644 --- a/00-backend/src/main/java/de/htwsaar/webshop/config/ControllerPathConfig.java +++ b/00-backend/src/main/java/de/htwsaar/webshop/config/ControllerPathConfig.java @@ -49,5 +49,6 @@ public class ControllerPathConfig { 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"; + public static final String STATISTICS_ORDERSTATUS = STATISTICS_BASE + "/orderstatus"; } \ No newline at end of file diff --git a/00-backend/src/main/java/de/htwsaar/webshop/controller/StatisticsController.java b/00-backend/src/main/java/de/htwsaar/webshop/controller/StatisticsController.java index bc68251..3c1e3e6 100644 --- a/00-backend/src/main/java/de/htwsaar/webshop/controller/StatisticsController.java +++ b/00-backend/src/main/java/de/htwsaar/webshop/controller/StatisticsController.java @@ -1,6 +1,7 @@ package de.htwsaar.webshop.controller; import de.htwsaar.webshop.model.CatMonthModel; +import de.htwsaar.webshop.model.OrderStatus; import de.htwsaar.webshop.service.SessionService; import de.htwsaar.webshop.service.StatisticsService; import jakarta.servlet.http.HttpServletRequest; @@ -11,10 +12,10 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.Map; 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.ControllerPathConfig.*; 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; @@ -55,4 +56,16 @@ public class StatisticsController { return ResponseEntity.ok(statisticsService.getSalesRevenue()); } + @RequestMapping(value = STATISTICS_ORDERSTATUS, method = RequestMethod.GET, produces = "application/json") + public ResponseEntity> getOrderStatus(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.getOrderStatus()); + } + } diff --git a/00-backend/src/main/java/de/htwsaar/webshop/service/StatisticsService.java b/00-backend/src/main/java/de/htwsaar/webshop/service/StatisticsService.java index 1801fbb..8c1480b 100644 --- a/00-backend/src/main/java/de/htwsaar/webshop/service/StatisticsService.java +++ b/00-backend/src/main/java/de/htwsaar/webshop/service/StatisticsService.java @@ -1,10 +1,15 @@ package de.htwsaar.webshop.service; import de.htwsaar.webshop.model.CatMonthModel; +import de.htwsaar.webshop.model.OrderStatus; + +import java.util.Map; public interface StatisticsService { CatMonthModel getSalesVolume(); CatMonthModel getSalesRevenue(); + Map getOrderStatus(); + } diff --git a/00-backend/src/main/java/de/htwsaar/webshop/service/impl/StatisticsServiceImpl.java b/00-backend/src/main/java/de/htwsaar/webshop/service/impl/StatisticsServiceImpl.java index d853be5..9cb7bc4 100644 --- a/00-backend/src/main/java/de/htwsaar/webshop/service/impl/StatisticsServiceImpl.java +++ b/00-backend/src/main/java/de/htwsaar/webshop/service/impl/StatisticsServiceImpl.java @@ -2,6 +2,7 @@ package de.htwsaar.webshop.service.impl; import de.htwsaar.webshop.model.ArticleCategory; import de.htwsaar.webshop.model.CatMonthModel; +import de.htwsaar.webshop.model.OrderStatus; import de.htwsaar.webshop.repository.entities.OrderItem; import de.htwsaar.webshop.service.OrderService; import de.htwsaar.webshop.service.StatisticsService; @@ -57,4 +58,14 @@ public class StatisticsServiceImpl implements StatisticsService { public CatMonthModel getSalesRevenue() { return getMonthCategoryMap(item -> item.getArticle().getPrice100(), Integer::sum, 0); } + + @Override + public Map getOrderStatus() { + Map map = new TreeMap<>(); + orderService.findAll().forEach(order -> { + map.putIfAbsent(order.getStatus(), 0); + map.computeIfPresent(order.getStatus(), (k,v) -> ++v); + }); + return map; + } } diff --git a/01-frontend/src/helper/adminpanel/StatisticsInfo.tsx b/01-frontend/src/helper/adminpanel/StatisticsInfo.tsx index ae8d647..36516dc 100644 --- a/01-frontend/src/helper/adminpanel/StatisticsInfo.tsx +++ b/01-frontend/src/helper/adminpanel/StatisticsInfo.tsx @@ -5,8 +5,9 @@ import { BarSeriesType } from '@mui/x-charts' import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useQuery } from "@tanstack/react-query"; -import { fetchStatisticsVolume, fetchStatisticsRevenue } from "../query/Queries.tsx"; +import { fetchStatisticsVolume, fetchStatisticsRevenue, fetchOrderStatus } from "../query/Queries.tsx"; import { useAccount } from "../AccountProvider.tsx"; +import { data } from "react-router-dom"; export default function StatisticsInfo() { const theme = useTheme(); @@ -14,16 +15,17 @@ export default function StatisticsInfo() { const [monthlyVolume, setMonthlyVolume] = useState([]); const [monthlyVolumeXaxis, setMonthlyVolumeXaxis] = useState([{ data: [] }]); - const [totalVolume, setTotalVolume] = useState([{ data: [] }]); + const [totalVolume, setTotalVolume] = useState([]); const [monthlyRevenue, setMonthlyRevenue] = useState([]); const [monthlyRevenueXaxis, setMonthlyRevenueXaxis] = useState([{ data: [] }]); - const [totalRevenue, setTotalRevenue] = useState([{ data: [] }]); - + const [totalRevenue, setTotalRevenue] = useState([]); + const [orderStatus, setOrderStatus] = useState([]); const { user: loginData } = useAccount(); + const { data: dataVolume } = useQuery({ queryKey: ["fetchStatisticsVolume", loginData], queryFn: () => fetchStatisticsVolume(loginData ? loginData : { email: "", password: "", session: "", customerId: -1, isAdmin: false }), @@ -38,15 +40,23 @@ export default function StatisticsInfo() { retryDelay: 0, }); + const { data: dataOrderStatus } = useQuery({ + queryKey: ["fetchOrderStatus", loginData], + queryFn: () => fetchOrderStatus(loginData ? loginData : { email: "", password: "", session: "", customerId: -1, isAdmin: false }), + retry: 0, + retryDelay: 0, + }); + + + useEffect(() => { if (dataVolume) { const cmm = [] const cmmx = monthlyVolumeXaxis - const tv = [{data:[]}] + const tv = [] let i = 0 for (const cat in dataVolume.catMonthMap) { for (const timestamp in dataVolume.catMonthMap[cat]) { - console.log(i + "." + timestamp); const date = new Date(parseInt(timestamp)) const formattedDate = date.getFullYear() + "-" + String(date.getMonth() + 1).padStart(2, '0') if (!cmmx[0].data.includes(formattedDate)) { @@ -58,10 +68,10 @@ export default function StatisticsInfo() { } cmm[i].data.push(datapoint) - if(tv[0].data.length == i) { - tv[0].data.push({ id: i, value: 0, label: t(cat)}) + if(tv.length == i) { + tv.push({ id: i, value: 0, label: t(cat)}) } - tv[0].data[i].value += datapoint + tv[i].value += datapoint } i++; } @@ -76,7 +86,7 @@ export default function StatisticsInfo() { if (dataRevenue) { const cmm = [] const cmmx = monthlyRevenueXaxis - const tv = [{data:[]}] + const tv = [] let i = 0 for (const cat in dataRevenue.catMonthMap) { for (const timestamp in dataRevenue.catMonthMap[cat]) { @@ -85,16 +95,16 @@ export default function StatisticsInfo() { if (!cmmx[0].data.includes(formattedDate)) { cmmx[0].data.push(formattedDate); } - const datapoint = dataRevenue.catMonthMap[cat][timestamp] + const datapoint = dataRevenue.catMonthMap[cat][timestamp] / 100 if(cmm.length == i) { cmm.push({ id: i, data: [], label: t(cat), type: "bar" }) } cmm[i].data.push(datapoint) - if(tv[0].data.length == i) { - tv[0].data.push({ id: i, value: 0, label: t(cat)}) + if(tv.length == i) { + tv.push({ id: i, value: 0, label: t(cat)}) } - tv[0].data[i].value += datapoint + tv[i].value += datapoint } i++; } @@ -105,6 +115,16 @@ export default function StatisticsInfo() { } }, [dataRevenue]); + useEffect(() => { + if(dataOrderStatus) { + const orderStatus = [] + for(var status in dataOrderStatus) { + orderStatus.push({value: dataOrderStatus[status], label: t(status)}) + } + setOrderStatus(orderStatus) + } + }, [dataOrderStatus]) + return ( @@ -132,27 +152,64 @@ export default function StatisticsInfo() { /> - + Item Volume Distribution - + Item Revenue Distribution + + + Stock fulfillment + + + + + + Order Status + + + ); diff --git a/01-frontend/src/helper/helper.css b/01-frontend/src/helper/helper.css index 2d35240..0e44c1e 100644 --- a/01-frontend/src/helper/helper.css +++ b/01-frontend/src/helper/helper.css @@ -29,4 +29,8 @@ .rating-text-field{ background-color: whitesmoke; +} + +.vw20 { + width: 20vw; } \ No newline at end of file diff --git a/01-frontend/src/helper/query/Queries.tsx b/01-frontend/src/helper/query/Queries.tsx index e76d186..f38d2c4 100644 --- a/01-frontend/src/helper/query/Queries.tsx +++ b/01-frontend/src/helper/query/Queries.tsx @@ -206,4 +206,12 @@ export const orderPatch = async (order: OrderPatch) => { throw new Error("Order patch failed"); } return response.json(); +}; + +export const fetchOrderStatus = async (loginData: User) => { + const response = await fetch("http://localhost:8085/statistics/orderstatus?email=" + loginData.email + "&session=" + loginData.session); + if (!response.ok) { + throw new Error("fetching satistics Revenue failed"); + } + return response.json(); }; \ No newline at end of file