133 lines
3.8 KiB
Go
133 lines
3.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"gestion/db"
|
|
"gestion/models"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
var weekdayNames = []string{"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"}
|
|
|
|
// GetAdminStats returns aggregated order & product statistics for the admin dashboard.
|
|
func GetAdminStats(c *gin.Context) {
|
|
database := c.MustGet("database").(*db.Database)
|
|
gdb := database.GDB
|
|
|
|
// ── Commandes par jour de la semaine (all time, non annulées) ──────────────
|
|
var wdRows []models.WeekdayRow
|
|
gdb.Raw(`
|
|
SELECT EXTRACT(DOW FROM created_at)::int AS dow, COUNT(*) AS count
|
|
FROM commandes
|
|
WHERE status != 'cancelled'
|
|
GROUP BY dow
|
|
ORDER BY dow
|
|
`).Scan(&wdRows)
|
|
|
|
byWeekday := make([]gin.H, 7)
|
|
wdMap := make(map[int]int, len(wdRows))
|
|
for _, r := range wdRows {
|
|
wdMap[r.DOW] = r.Count
|
|
}
|
|
peakCount, peakWeekday := 0, ""
|
|
for i := 0; i < 7; i++ {
|
|
cnt := wdMap[i]
|
|
byWeekday[i] = gin.H{"weekday": weekdayNames[i], "count": cnt}
|
|
if cnt > peakCount {
|
|
peakCount = cnt
|
|
peakWeekday = weekdayNames[i]
|
|
}
|
|
}
|
|
|
|
// ── Commandes par jour sur 30 jours ───────────────────────────────────────
|
|
var dayRows []models.DayRow
|
|
gdb.Raw(`
|
|
SELECT DATE(created_at) AS day, COUNT(*) AS count
|
|
FROM commandes
|
|
WHERE created_at >= NOW() - INTERVAL '30 days'
|
|
AND status != 'cancelled'
|
|
GROUP BY DATE(created_at)
|
|
ORDER BY day
|
|
`).Scan(&dayRows)
|
|
|
|
byDay := make([]gin.H, len(dayRows))
|
|
for i, r := range dayRows {
|
|
byDay[i] = gin.H{
|
|
"day": r.Day.Format("2006-01-02"),
|
|
"label": r.Day.Format("02/01"),
|
|
"count": r.Count,
|
|
}
|
|
}
|
|
|
|
// ── Top produits (quantité vendue, commandes terminées) ───────────────────
|
|
var prodRows []models.ProductRow
|
|
gdb.Raw(`
|
|
SELECT
|
|
ci.product_id,
|
|
ci.produit AS name,
|
|
SUM(ci.quantite) AS total_quantity,
|
|
COUNT(DISTINCT ci.command_id) AS order_count,
|
|
SUM(ci.prix * ci.quantite) AS revenue
|
|
FROM command_items ci
|
|
JOIN commandes c ON c.id = ci.command_id
|
|
WHERE c.status != 'cancelled'
|
|
GROUP BY ci.product_id, ci.produit
|
|
ORDER BY total_quantity DESC
|
|
LIMIT 15
|
|
`).Scan(&prodRows)
|
|
|
|
topProducts := make([]gin.H, len(prodRows))
|
|
topProductName := ""
|
|
for i, r := range prodRows {
|
|
topProducts[i] = gin.H{
|
|
"product_id": r.ProductID,
|
|
"name": r.Name,
|
|
"quantity": r.Quantity,
|
|
"order_count": r.OrderCount,
|
|
"revenue": r.Revenue,
|
|
}
|
|
if i == 0 {
|
|
topProductName = r.Name
|
|
}
|
|
}
|
|
|
|
// ── Résumé global ─────────────────────────────────────────────────────────
|
|
var totalOrders int64
|
|
var totalRevenue float64
|
|
gdb.Raw(`SELECT COUNT(*) FROM commandes WHERE status != 'cancelled'`).Scan(&totalOrders)
|
|
gdb.Raw(`SELECT COALESCE(SUM(total_prix), 0) FROM commandes WHERE status = 'approved'`).Scan(&totalRevenue)
|
|
|
|
avgPerDay := 0.0
|
|
if totalOrders > 0 {
|
|
// average over the last 30 days with data
|
|
var activeDays int64
|
|
gdb.Raw(`
|
|
SELECT COUNT(DISTINCT DATE(created_at))
|
|
FROM commandes
|
|
WHERE created_at >= NOW() - INTERVAL '30 days' AND status != 'cancelled'
|
|
`).Scan(&activeDays)
|
|
if activeDays > 0 {
|
|
var last30Count int64
|
|
gdb.Raw(`
|
|
SELECT COUNT(*) FROM commandes
|
|
WHERE created_at >= NOW() - INTERVAL '30 days' AND status != 'cancelled'
|
|
`).Scan(&last30Count)
|
|
avgPerDay = float64(last30Count) / float64(activeDays)
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"summary": gin.H{
|
|
"total_orders": totalOrders,
|
|
"total_revenue": totalRevenue,
|
|
"peak_weekday": peakWeekday,
|
|
"top_product": topProductName,
|
|
"avg_per_day": avgPerDay,
|
|
},
|
|
"by_weekday": byWeekday,
|
|
"by_day_30": byDay,
|
|
"top_products": topProducts,
|
|
})
|
|
}
|