From a9fc3e32273b69a5be906b60e037e82a203e1840 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sun, 29 Mar 2026 23:34:52 -0600 Subject: [PATCH] Show staff analytics --- .../api/dto/analytics/DashboardResponse.java | 69 ++++++++++++++++++ .../petshopdesktop/auth/UserSession.java | 4 ++ .../controllers/AnalyticsController.java | 71 ++++++++----------- .../controllers/MainLayoutController.java | 5 +- 4 files changed, 104 insertions(+), 45 deletions(-) diff --git a/desktop/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java b/desktop/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java index 1b29b2b3..38b17b81 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java +++ b/desktop/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java @@ -8,6 +8,8 @@ public class DashboardResponse { private InventorySummary inventorySummary; private List topProducts; private List dailySales; + private List paymentMethods; + private List employeePerformance; public DashboardResponse() { } @@ -44,11 +46,28 @@ public class DashboardResponse { this.dailySales = dailySales; } + public List getPaymentMethods() { + return paymentMethods; + } + + public void setPaymentMethods(List paymentMethods) { + this.paymentMethods = paymentMethods; + } + + public List getEmployeePerformance() { + return employeePerformance; + } + + public void setEmployeePerformance(List employeePerformance) { + this.employeePerformance = employeePerformance; + } + public static class SalesSummary { private BigDecimal totalRevenue; private Long totalSales; private BigDecimal totalRefunds; private Long totalRefundCount; + private Long totalItemsSold; public SalesSummary() { } @@ -84,6 +103,14 @@ public class DashboardResponse { public void setTotalRefundCount(Long totalRefundCount) { this.totalRefundCount = totalRefundCount; } + + public Long getTotalItemsSold() { + return totalItemsSold; + } + + public void setTotalItemsSold(Long totalItemsSold) { + this.totalItemsSold = totalItemsSold; + } } public static class InventorySummary { @@ -118,4 +145,46 @@ public class DashboardResponse { this.outOfStockProducts = outOfStockProducts; } } + + public static class PaymentMethodData { + private String paymentMethod; + private Long count; + + public String getPaymentMethod() { + return paymentMethod; + } + + public void setPaymentMethod(String paymentMethod) { + this.paymentMethod = paymentMethod; + } + + public Long getCount() { + return count; + } + + public void setCount(Long count) { + this.count = count; + } + } + + public static class EmployeePerformanceData { + private String employeeName; + private BigDecimal revenue; + + public String getEmployeeName() { + return employeeName; + } + + public void setEmployeeName(String employeeName) { + this.employeeName = employeeName; + } + + public BigDecimal getRevenue() { + return revenue; + } + + public void setRevenue(BigDecimal revenue) { + this.revenue = revenue; + } + } } diff --git a/desktop/src/main/java/org/example/petshopdesktop/auth/UserSession.java b/desktop/src/main/java/org/example/petshopdesktop/auth/UserSession.java index a578d0e4..cd5646f4 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/auth/UserSession.java +++ b/desktop/src/main/java/org/example/petshopdesktop/auth/UserSession.java @@ -92,4 +92,8 @@ public class UserSession { public boolean isAdmin() { return Role.ADMIN.equals(role); } + + public boolean isStaff() { + return Role.STAFF.equals(role); + } } diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java index 1ab0ffbe..dcae41df 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java @@ -9,9 +9,8 @@ import javafx.scene.control.Label; import org.example.petshopdesktop.api.dto.analytics.DailySales; import org.example.petshopdesktop.api.dto.analytics.DashboardResponse; import org.example.petshopdesktop.api.dto.analytics.TopProduct; -import org.example.petshopdesktop.api.dto.sale.SaleResponse; import org.example.petshopdesktop.api.endpoints.AnalyticsApi; -import org.example.petshopdesktop.api.endpoints.SaleApi; +import org.example.petshopdesktop.auth.UserSession; import org.example.petshopdesktop.util.ActivityLogger; import java.math.BigDecimal; @@ -127,16 +126,17 @@ public class AnalyticsController { new Thread(() -> { try { DashboardResponse dashboard = AnalyticsApi.getInstance().getDashboard(30, 10); - List sales = SaleApi.getInstance().listSales(0, Integer.MAX_VALUE, null); Platform.runLater(() -> { try { + boolean isAdmin = UserSession.getInstance().isAdmin(); loadSummaryData(dashboard); loadSalesOverTime(dashboard); loadTopProductsByRevenue(dashboard); loadTopProductsByQuantity(dashboard); - loadPaymentMethodDistribution(sales); - loadEmployeePerformance(sales); + loadPaymentMethodDistribution(dashboard); + loadEmployeePerformance(dashboard, isAdmin); + applyRoleVisibility(isAdmin); } catch (Exception e) { ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data"); lblError.setText("Error loading analytics data. Please try again."); @@ -157,15 +157,12 @@ public class AnalyticsController { if (dashboard != null) { BigDecimal totalRevenue = BigDecimal.ZERO; Long totalSales = 0L; - Long totalProducts = 0L; - if (dashboard.getSalesSummary() != null) { totalRevenue = dashboard.getSalesSummary().getTotalRevenue() != null ? dashboard.getSalesSummary().getTotalRevenue() : BigDecimal.ZERO; totalSales = dashboard.getSalesSummary().getTotalSales() != null ? dashboard.getSalesSummary().getTotalSales() : 0L; - } - - if (dashboard.getInventorySummary() != null) { - totalProducts = dashboard.getInventorySummary().getTotalProducts() != null ? dashboard.getInventorySummary().getTotalProducts() : 0L; + lblTotalItems.setText(wholeNumber.format(dashboard.getSalesSummary().getTotalItemsSold() != null ? dashboard.getSalesSummary().getTotalItemsSold() : 0L)); + } else { + lblTotalItems.setText(wholeNumber.format(0)); } lblTotalRevenue.setText(currency.format(totalRevenue)); @@ -176,7 +173,6 @@ public class AnalyticsController { avgTransaction = totalRevenue.divide(BigDecimal.valueOf(totalSales), 2, RoundingMode.HALF_UP); } lblAvgTransaction.setText(currency.format(avgTransaction)); - lblTotalItems.setText(wholeNumber.format(totalProducts)); } } @@ -243,24 +239,14 @@ public class AnalyticsController { applyBarChartColor(chartTopQuantity, QUANTITY_COLOR); } - private void loadPaymentMethodDistribution(List sales) throws Exception { - Map paymentMethodCount = sales.stream() - .filter(sale -> sale.getIsRefund() == null || !sale.getIsRefund()) - .collect(Collectors.groupingBy( - sale -> sale.getPaymentMethod() != null ? sale.getPaymentMethod() : "Unknown", - Collectors.counting() - )); - + private void loadPaymentMethodDistribution(DashboardResponse dashboard) throws Exception { chartPaymentMethods.getData().clear(); - List> paymentEntries = paymentMethodCount.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .toList(); - - for (Map.Entry entry : paymentEntries) { + List paymentEntries = dashboard.getPaymentMethods() != null ? dashboard.getPaymentMethods() : List.of(); + for (DashboardResponse.PaymentMethodData entry : paymentEntries) { PieChart.Data slice = new PieChart.Data( - entry.getKey() + " (" + entry.getValue() + ")", - entry.getValue() + entry.getPaymentMethod() + " (" + entry.getCount() + ")", + entry.getCount() ); chartPaymentMethods.getData().add(slice); } @@ -269,24 +255,14 @@ public class AnalyticsController { applyPieChartColors(); } - private void loadEmployeePerformance(List sales) throws Exception { - Map employeeRevenue = sales.stream() - .filter(sale -> sale.getIsRefund() == null || !sale.getIsRefund()) - .filter(sale -> sale.getEmployeeName() != null) - .collect(Collectors.groupingBy( - SaleResponse::getEmployeeName, - Collectors.summingDouble(sale -> sale.getTotalAmount() != null ? sale.getTotalAmount().doubleValue() : 0.0) - )); - + private void loadEmployeePerformance(DashboardResponse dashboard, boolean isAdmin) throws Exception { XYChart.Series series = new XYChart.Series<>(); - series.setName("Revenue"); + series.setName(isAdmin ? "Revenue" : "My Revenue"); - List> employeeEntries = employeeRevenue.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .toList(); - - for (Map.Entry entry : employeeEntries) { - series.getData().add(new XYChart.Data<>(entry.getKey(), entry.getValue())); + List employeeEntries = dashboard.getEmployeePerformance() != null ? dashboard.getEmployeePerformance() : List.of(); + for (DashboardResponse.EmployeePerformanceData entry : employeeEntries) { + BigDecimal revenue = entry.getRevenue() != null ? entry.getRevenue() : BigDecimal.ZERO; + series.getData().add(new XYChart.Data<>(entry.getEmployeeName(), revenue)); } chartEmployeePerformance.getData().clear(); @@ -294,6 +270,15 @@ public class AnalyticsController { applyBarChartColor(chartEmployeePerformance, EMPLOYEE_COLOR); } + private void applyRoleVisibility(boolean isAdmin) { + chartEmployeePerformance.setVisible(isAdmin); + chartEmployeePerformance.setManaged(isAdmin); + if (chartEmployeePerformance.getParent() != null) { + chartEmployeePerformance.getParent().setVisible(isAdmin); + chartEmployeePerformance.getParent().setManaged(isAdmin); + } + } + private void applyLineChartColor(LineChart chart, String color) { Platform.runLater(() -> { for (XYChart.Series series : chart.getData()) { diff --git a/desktop/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java b/desktop/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java index d87e181d..4481bc9c 100644 --- a/desktop/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java +++ b/desktop/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java @@ -358,6 +358,7 @@ public class MainLayoutController { lblRole.setText("Leon's Petstore"); boolean isAdmin = session.isAdmin(); + boolean canViewAnalytics = isAdmin || session.isStaff(); btnInventory.setVisible(isAdmin); btnInventory.setManaged(isAdmin); btnSuppliers.setVisible(isAdmin); @@ -384,8 +385,8 @@ public class MainLayoutController { } if (btnAnalytics != null) { - btnAnalytics.setVisible(isAdmin); - btnAnalytics.setManaged(isAdmin); + btnAnalytics.setVisible(canViewAnalytics); + btnAnalytics.setManaged(canViewAnalytics); } btnSalesHistory.setText(isAdmin ? "Sales History" : "Sales");