diff --git a/backend/src/main/java/com/rit/canteen/sales/BackendApplication.java b/backend/src/main/java/com/rit/canteen/sales/BackendApplication.java index 3cb14c90..b6fab5cb 100644 --- a/backend/src/main/java/com/rit/canteen/sales/BackendApplication.java +++ b/backend/src/main/java/com/rit/canteen/sales/BackendApplication.java @@ -16,4 +16,9 @@ public class BackendApplication { SpringApplication.run(BackendApplication.class, args); } + @jakarta.annotation.PostConstruct + public void init() { + java.util.TimeZone.setDefault(java.util.TimeZone.getTimeZone("Asia/Kolkata")); + System.out.println("[TIMEZONE] Global JVM TimeZone set to: " + java.util.TimeZone.getDefault().getID()); + } } diff --git a/backend/src/main/java/com/rit/canteen/sales/controller/OrderController.java b/backend/src/main/java/com/rit/canteen/sales/controller/OrderController.java index 8f717950..39a85f4a 100644 --- a/backend/src/main/java/com/rit/canteen/sales/controller/OrderController.java +++ b/backend/src/main/java/com/rit/canteen/sales/controller/OrderController.java @@ -128,6 +128,10 @@ public class OrderController { @PostMapping @org.springframework.transaction.annotation.Transactional public ResponseEntity placeOrder(@RequestBody Order order) { + System.out.println("[REVENUE-TRACE] Incoming Place Order Request -> User: " + order.getUserId() + + " | Total: " + order.getTotalAmount() + + " | Items: " + (order.getItems() != null ? order.getItems().size() : 0)); + // 1. Pre-validation and linking if (order.getItems() == null || order.getItems().isEmpty()) { return ResponseEntity.badRequest().body(Map.of("success", false, "message", "Order must have items")); @@ -164,6 +168,9 @@ public class OrderController { // 3. Complete Order Details for (OrderItem item : order.getItems()) { item.setOrder(order); + if (item.getStallName() == null || item.getStallName().isEmpty() || item.getStallName().equals("Unknown Stall")) { + item.setStallName("RIT Canteen"); + } } LocalDateTime now = LocalDateTime.now(); @@ -189,7 +196,16 @@ public class OrderController { // 5. Final Save Order savedOrder = orderRepository.save(order); - System.out.println("Placed Order: " + savedOrder.getId() + " -> Display ID: #" + displayId); + System.out.println("[REVENUE-TRACE] Saved Order: " + savedOrder.getOrderNumber() + + " | Display ID: #" + savedOrder.getDisplayOrderId() + + " | CreatedAt: " + savedOrder.getCreatedAt() + + " | Payment: " + savedOrder.getPaymentMethod()); + + if (savedOrder.getItems() != null) { + savedOrder.getItems().forEach(item -> + System.out.println("[REVENUE-TRACE] Saved Item: " + item.getProductName() + + " | Stall: " + item.getStallName())); + } return ResponseEntity.ok(Map.of( "success", true, diff --git a/backend/src/main/java/com/rit/canteen/sales/model/TrendingItem.java b/backend/src/main/java/com/rit/canteen/sales/model/TrendingItem.java index eaae94c5..f6fa4e7e 100644 --- a/backend/src/main/java/com/rit/canteen/sales/model/TrendingItem.java +++ b/backend/src/main/java/com/rit/canteen/sales/model/TrendingItem.java @@ -3,16 +3,16 @@ package com.rit.canteen.sales.model; public class TrendingItem { private String name; private String category; - private long qty; - private String image; + private long orderCount; + private String imageUrl; public TrendingItem() {} - public TrendingItem(String name, String category, long qty, String image) { + public TrendingItem(String name, String category, long orderCount, String imageUrl) { this.name = name; this.category = category; - this.qty = qty; - this.image = image; + this.orderCount = orderCount; + this.imageUrl = imageUrl; } public String getName() { return name; } @@ -21,9 +21,9 @@ public class TrendingItem { public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } - public long getQty() { return qty; } - public void setQty(long qty) { this.qty = qty; } + public long getOrderCount() { return orderCount; } + public void setOrderCount(long orderCount) { this.orderCount = orderCount; } - public String getImage() { return image; } - public void setImage(String image) { this.image = image; } + public String getImageUrl() { return imageUrl; } + public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } } diff --git a/backend/src/main/java/com/rit/canteen/sales/service/DashboardService.java b/backend/src/main/java/com/rit/canteen/sales/service/DashboardService.java index 249836d9..6730e26a 100644 --- a/backend/src/main/java/com/rit/canteen/sales/service/DashboardService.java +++ b/backend/src/main/java/com/rit/canteen/sales/service/DashboardService.java @@ -35,8 +35,9 @@ public class DashboardService { private TokenTransactionRepository tokenTransactionRepository; public GeneralDashboardData getGeneralDashboardData(LocalDateTime from, LocalDateTime to) { - if (from == null) from = LocalDate.now().atStartOfDay(); - if (to == null) to = LocalDate.now().atTime(LocalTime.MAX); + java.time.ZoneId zone = java.time.ZoneId.of("Asia/Kolkata"); + if (from == null) from = java.time.LocalDate.now(zone).atStartOfDay(); + if (to == null) to = java.time.LocalDate.now(zone).atTime(java.time.LocalTime.MAX); System.out.println("[DIAGNOSTIC] Final timestamp range for service logic: " + from + " to " + to); DashboardStats stats = getDashboardStats(from, to); @@ -47,11 +48,17 @@ public class DashboardService { List> storeOverview = new ArrayList<>(); for (Object[] row : storeData) { Map store = new HashMap<>(); - store.put("name", row[0] != null ? row[0] : "Unknown Stall"); - store.put("sale", row[1] != null ? row[1] : 0); - store.put("orders", row[2] != null ? row[2] : 0); - store.put("taxes", 0); // Placeholder - store.put("purchase", 0); // Placeholder + String stallName = (row[0] != null && !row[0].toString().equals("Unknown Stall")) ? row[0].toString() : "RIT Canteen"; + BigDecimal saleVal = row[1] != null ? (BigDecimal) row[1] : BigDecimal.ZERO; + long orderCount = row[2] != null ? ((Number) row[2]).longValue() : 0; + + System.out.println("[REVENUE-TRACE] Store Overview Result -> Stall: " + stallName + " | Sales: " + saleVal + " | Orders: " + orderCount); + + store.put("name", stallName); + store.put("sale", saleVal); + store.put("orders", orderCount); + store.put("taxes", 0); + store.put("purchase", 0); storeOverview.add(store); } @@ -86,7 +93,7 @@ public class DashboardService { String imageData = (String) row[3]; // Format image data for frontend - String imageUrl = imageData != null ? (imageData.startsWith("http") ? imageData : (imageData.startsWith("data:") ? imageData : "data:image/png;base64," + imageData)) : "https://images.unsplash.com/photo-1546069901-ba9599a7e63c?w=200&q=80"; + String imageUrl = imageData != null ? (imageData.startsWith("http") ? imageData : (imageData.startsWith("data:") ? imageData : "data:image/png;base64," + imageData)) : null; trendingItems.add(new TrendingItem(name, category, qty, imageUrl)); } @@ -103,7 +110,7 @@ public class DashboardService { ? BigDecimal.valueOf(stats.getTotalSales()).divide(BigDecimal.valueOf(stats.getActiveOrders()), 2, RoundingMode.HALF_UP) : BigDecimal.ZERO; Map avgInsight = new HashMap<>(); - avgInsight.put("text", "₹" + avg + " average order value! Either everyone's hungry or just living large 🔥😋"); + avgInsight.put("text", "R" + avg + " average order value! Either everyone's hungry or just living large 🔥😋"); avgInsight.put("color", "bg-emerald-50 text-emerald-600 border-emerald-100"); insights.add(avgInsight); @@ -113,7 +120,7 @@ public class DashboardService { insights.add(customerInsight); Map revenueInsight = new HashMap<>(); - revenueInsight.put("text", "RIT Canteen clocked ₹" + String.format("%,d", stats.getTotalSales()) + " — ka-ching! That's called business booming 💸📈"); + revenueInsight.put("text", "RIT Canteen clocked R" + String.format("%,d", stats.getTotalSales()) + " — ka-ching! That's called business booming 💸📈"); revenueInsight.put("color", "bg-blue-50 text-blue-600 border-blue-100"); insights.add(revenueInsight); } else { @@ -128,11 +135,13 @@ public class DashboardService { } public DashboardStats getDashboardStats(LocalDateTime from, LocalDateTime to) { - LocalDateTime startOfToday = LocalDate.now().atStartOfDay(); - LocalDateTime endOfToday = LocalDate.now().atTime(LocalTime.MAX); + System.out.println("[REVENUE-TRACE] Dashboard Request Range: " + from + " to " + to); + java.time.ZoneId zone = java.time.ZoneId.of("Asia/Kolkata"); + LocalDateTime startOfToday = LocalDate.now(zone).atStartOfDay(); + LocalDateTime endOfToday = LocalDate.now(zone).atTime(LocalTime.MAX); - LocalDateTime startOfYesterday = LocalDate.now().minusDays(1).atStartOfDay(); - LocalDateTime endOfYesterday = LocalDate.now().minusDays(1).atTime(LocalTime.MAX); + LocalDateTime startOfYesterday = LocalDate.now(zone).minusDays(1).atStartOfDay(); + LocalDateTime endOfYesterday = LocalDate.now(zone).minusDays(1).atTime(LocalTime.MAX); System.out.println("[DIAGNOSTIC] Fetching Total Revenue..."); BigDecimal totalRevenueRaw = tokenTransactionRepository.sumByType(com.rit.canteen.sales.model.TokenTransaction.TransactionType.TOPUP); @@ -146,6 +155,8 @@ public class DashboardService { int activeOrders = (int) orderRepository.countByCreatedAtBetween(from, to); int dailyCustomers = (int) orderRepository.countUniqueUsersInRange(from, to); + + System.out.println("[REVENUE-TRACE] Active Orders in Range: " + activeOrders + " | Unique Customers: " + dailyCustomers); BigDecimal todayRevenue = tokenTransactionRepository.sumByTypeInRange(com.rit.canteen.sales.model.TokenTransaction.TransactionType.TOPUP, startOfToday, endOfToday); BigDecimal yesterdayRevenue = tokenTransactionRepository.sumByTypeInRange(com.rit.canteen.sales.model.TokenTransaction.TransactionType.TOPUP, startOfYesterday, endOfYesterday); diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index a33d933f..4e08cb1a 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -9,6 +9,7 @@ spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.jdbc.time_zone=Asia/Kolkata # Master Account Credentials app.master.username=admin diff --git a/frontend/src/pages/ArchivedOrders.tsx b/frontend/src/pages/ArchivedOrders.tsx index 8a722172..3d992850 100644 --- a/frontend/src/pages/ArchivedOrders.tsx +++ b/frontend/src/pages/ArchivedOrders.tsx @@ -213,7 +213,7 @@ const ArchivedOrders: React.FC = () => {
Grand Total
-
R{order.totalAmount.toFixed(2)}
+
₹{order.totalAmount.toFixed(2)}
@@ -325,8 +325,8 @@ const ArchivedOrders: React.FC = () => {
-
R{(item.price * item.quantity).toLocaleString()}
-
@ R{item.price}
+
₹{(item.price * item.quantity).toLocaleString()}
+
@ ₹{item.price}
))} @@ -377,7 +377,7 @@ const ArchivedOrders: React.FC = () => {
Final Settlement
-
R{selectedOrder.totalAmount.toLocaleString()}
+
₹{selectedOrder.totalAmount.toLocaleString()}
Transaction Fully Reconciled
diff --git a/frontend/src/pages/Customers.tsx b/frontend/src/pages/Customers.tsx index 5e5af612..9a8f539f 100644 --- a/frontend/src/pages/Customers.tsx +++ b/frontend/src/pages/Customers.tsx @@ -279,13 +279,13 @@ const Customers: React.FC = () => { - R{user.ritzTokenBalance?.toLocaleString() || '0'} + ₹{user.ritzTokenBalance?.toLocaleString() || '0'} - R{user.ritzTokenBalance?.toLocaleString() || '0'} + ₹{user.ritzTokenBalance?.toLocaleString() || '0'} @@ -364,7 +364,7 @@ const Customers: React.FC = () => { RIT STUDENT - R{user.ritzTokenBalance?.toLocaleString() || '0'} TOKENS + ₹{user.ritzTokenBalance?.toLocaleString() || '0'} TOKENS diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index ad1394fd..c1fe3d4f 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -224,7 +224,7 @@ const Dashboard = () => { - v >= 1000 ? `R${v/1000}k` : `R${v}`} /> + v >= 1000 ? `₹${v/1000}k` : `₹${v}`} /> @@ -262,9 +262,9 @@ const Dashboard = () => {
-

R{(stats.periodRevenue || 0).toLocaleString()}

+

₹{(stats.periodRevenue || 0).toLocaleString()}

{timeRange === 'Today' ? 'Today' : timeRange}

-

Total: R{(stats.totalSales || 0).toLocaleString()}

+

Total: ₹{(stats.totalSales || 0).toLocaleString()}

{pieData.map(item => ( @@ -365,13 +365,17 @@ const Dashboard = () => {
TOP #{idx+1}
-
- {item.name} -
+
+ {item.imageUrl ? ( + {item.name} + ) : ( +
+ )} +

{item.name}

@@ -401,7 +405,9 @@ const Dashboard = () => { key={idx} className={`p-5 rounded-2xl border transition-all cursor-default ${insight.color || 'border-slate-100 bg-slate-50/50 hover:bg-white hover:shadow-md hover:border-transparent'}`} > -

{insight.text || insight}

+

+ {(insight.text || insight).replace(/R(?=[0-9])/g, '₹')} +

))}
@@ -429,7 +435,7 @@ const Dashboard = () => {

Gross Sale

-

R{Number(store.sale).toLocaleString()}

+

₹{Number(store.sale).toLocaleString()}

Volume

diff --git a/frontend/src/pages/Orders.tsx b/frontend/src/pages/Orders.tsx index 4d4a7414..ffcace45 100644 --- a/frontend/src/pages/Orders.tsx +++ b/frontend/src/pages/Orders.tsx @@ -465,7 +465,7 @@ const Orders: React.FC = () => {
Grand Total
-
R{order.totalAmount.toFixed(2)}
+
₹{order.totalAmount.toFixed(2)}
@@ -628,9 +628,9 @@ const Orders: React.FC = () => {
-
R{(item.price * item.quantity).toLocaleString()}
+
₹{(item.price * item.quantity).toLocaleString()}
- {item.quantity} x R{item.price} + {item.quantity} x ₹{item.price}
@@ -700,7 +700,7 @@ const Orders: React.FC = () => {
Active Grand Total
-
R{selectedOrder.totalAmount.toLocaleString()}
+
₹{selectedOrder.totalAmount.toLocaleString()}
Transaction Pending Approval
@@ -784,7 +784,7 @@ const Orders: React.FC = () => {
{item.productName}
-
R{item.price} each
+
₹{item.price} each
@@ -805,7 +805,7 @@ const Orders: React.FC = () => {
-
R{(item.price * item.quantity).toFixed(2)}
+
₹{(item.price * item.quantity).toFixed(2)}
-
R{product.price}
+
₹{product.price}
)) ) : editSearchQuery ? ( @@ -866,7 +866,7 @@ const Orders: React.FC = () => {
New Order Total - R{editTotal.toFixed(2)} + ₹{editTotal.toFixed(2)}
- R{product.price} + ₹{product.price}
diff --git a/frontend/src/pages/Reports.tsx b/frontend/src/pages/Reports.tsx index 84ed75f3..4d242e05 100644 --- a/frontend/src/pages/Reports.tsx +++ b/frontend/src/pages/Reports.tsx @@ -105,10 +105,10 @@ const Reports: React.FC = () => { const summaryData = [ ['Metric', 'Value'], - ['Total Sales Revenue', `INR ${data.totalSales.toLocaleString()}`], + ['Total Sales Revenue', `₹ ${data.totalSales.toLocaleString()}`], ['Total Orders Fulfilled', data.totalOrders.toString()], - ['Total Inventory Purchases', `INR ${data.totalPurchases.toLocaleString()}`], - ['Net Performance', `INR ${(data.totalSales - data.totalPurchases).toLocaleString()}`], + ['Total Inventory Purchases', `₹ ${data.totalPurchases.toLocaleString()}`], + ['Net Performance', `₹ ${(data.totalSales - data.totalPurchases).toLocaleString()}`], ['Top Performing Vendor', data.topVendor] ]; @@ -126,7 +126,7 @@ const Reports: React.FC = () => { autoTable(doc, { startY: finalY1 + 20, head: [['Product Name', 'Quantity Sold', 'Revenue']], - body: data.topSellingItems.map(item => [item.name, item.quantity, `INR ${item.revenue.toLocaleString()}`]), + body: data.topSellingItems.map(item => [item.name, item.quantity, `₹ ${item.revenue.toLocaleString()}`]), theme: 'grid' }); @@ -136,7 +136,7 @@ const Reports: React.FC = () => { autoTable(doc, { startY: finalY2 + 20, head: [['Vendor Name', 'Total Orders', 'Spend Amount']], - body: data.vendorSummary.map(v => [v.name, v.orderCount, `INR ${v.amount.toLocaleString()}`]), + body: data.vendorSummary.map(v => [v.name, v.orderCount, `₹ ${v.amount.toLocaleString()}`]), theme: 'striped' }); diff --git a/frontend/src/pages/Stalls.tsx b/frontend/src/pages/Stalls.tsx index fd8779a4..9baf088e 100644 --- a/frontend/src/pages/Stalls.tsx +++ b/frontend/src/pages/Stalls.tsx @@ -639,7 +639,7 @@ const Stalls: React.FC = () => {

{product.name}

-

R{product.price} • {product.category}

+

₹{product.price} • {product.category}

diff --git a/frontend/src/pages/StoreDashboard.tsx b/frontend/src/pages/StoreDashboard.tsx index e80a6e74..d8a00d35 100644 --- a/frontend/src/pages/StoreDashboard.tsx +++ b/frontend/src/pages/StoreDashboard.tsx @@ -358,8 +358,12 @@ const StoreDashboard = () => {
-
- {item.name} +
+ {item.imageUrl ? ( + {item.name} + ) : ( +
+ )}

{item.category}

@@ -368,7 +372,7 @@ const StoreDashboard = () => {
- {item.qty} + {item.orderCount} ))}