package tests import ( "encoding/json" "gestion/handlers" "net/http" "net/http/httptest" "testing" "time" "github.com/gin-gonic/gin" ) // newTestDeliveredOrder crée une commande livrée/approuvée assignée à un // livreur avec une date de mise à jour contrôlée (GetMyDeliveryStats groupe // par updated_at, pas created_at). func newTestDeliveredOrder(t *testing.T, livreurUsername, clientUsername, status string, productID int, quantite, prix, referralUsed float64, updatedAt time.Time) { t.Helper() var cmdID int if err := testDB.GDB.Raw( `INSERT INTO commandes (username, status, livreur_assign, adresse, total_prix, referral_used, created_at, updated_at) VALUES (?, ?, ?, 'Adresse test', ?, ?, ?, ?) RETURNING id`, clientUsername, status, livreurUsername, prix, referralUsed, updatedAt, updatedAt, ).Scan(&cmdID).Error; err != nil { t.Fatalf("création commande livrée test: %v", err) } if err := testDB.GDB.Exec( `INSERT INTO command_items (command_id, product_id, produit, quantite, prix, status) VALUES (?, ?, 'item test', ?, ?, 'delivered')`, cmdID, productID, quantite, prix, ).Error; err != nil { t.Fatalf("création item commande livrée test: %v", err) } } func livreurStatsContext(username string) (*gin.Context, *httptest.ResponseRecorder) { req := httptest.NewRequest(http.MethodGet, "/api/v1/livreur/stats", nil) rec := httptest.NewRecorder() c, _ := gin.CreateTestContext(rec) c.Request = req c.Set("database", testDB) c.Set("username", username) c.Set("role", "livreur") return c, rec } type deliveryStatsResponse struct { Success bool `json:"success"` TodayCount int `json:"today_count"` TodayRevenue float64 `json:"today_revenue"` } // today_count/today_revenue ne doivent compter que les livraisons du jour // courant (livre/approved), nettes du crédit de parrainage — pas les jours // précédents, même récents (voir by_day/by_week qui eux les agrègent). func TestGetMyDeliveryStats_TodayCountAndRevenue(t *testing.T) { cleanupStockTestData(t) livreurUsername := newTestClient(t, "stats_livreur_today") clientUsername := newTestClient(t, "stats_livreur_today_client") productID := newTestProduct(t, "StatsLivreurToday", 100) now := time.Now() yesterday := now.AddDate(0, 0, -1) newTestDeliveredOrder(t, livreurUsername, clientUsername, "approved", productID, 2, 40, 10, now) // net 30, aujourd'hui newTestDeliveredOrder(t, livreurUsername, clientUsername, "approved", productID, 1, 25, 0, yesterday) // hier, ne doit pas compter dans "today" c, rec := livreurStatsContext(livreurUsername) handlers.GetMyDeliveryStats(c) if rec.Code != http.StatusOK { t.Fatalf("status HTTP: got=%d body=%s", rec.Code, rec.Body.String()) } var resp deliveryStatsResponse if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil { t.Fatalf("décodage réponse: %v body=%s", err, rec.Body.String()) } if !resp.Success { t.Fatalf("success=false, body=%s", rec.Body.String()) } if resp.TodayCount != 1 { t.Errorf("today_count: got=%d want=1 (la commande d'hier ne doit pas compter)", resp.TodayCount) } if resp.TodayRevenue != 30 { t.Errorf("today_revenue: got=%.2f want=30 (40 - 10 de parrainage)", resp.TodayRevenue) } } // Aucune livraison aujourd'hui : today_count/today_revenue doivent être 0, // pas une absence de champ (voir le bug initial où le seul indicateur de // "livraisons du jour" était l'absence de ligne dans by_day). func TestGetMyDeliveryStats_TodayCountZeroWhenNoDeliveryToday(t *testing.T) { cleanupStockTestData(t) livreurUsername := newTestClient(t, "stats_livreur_none") c, rec := livreurStatsContext(livreurUsername) handlers.GetMyDeliveryStats(c) if rec.Code != http.StatusOK { t.Fatalf("status HTTP: got=%d body=%s", rec.Code, rec.Body.String()) } var resp deliveryStatsResponse if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil { t.Fatalf("décodage réponse: %v body=%s", err, rec.Body.String()) } if resp.TodayCount != 0 { t.Errorf("today_count: got=%d want=0", resp.TodayCount) } if resp.TodayRevenue != 0 { t.Errorf("today_revenue: got=%.2f want=0", resp.TodayRevenue) } } // Seules les commandes assignées à CE livreur doivent être comptées. func TestGetMyDeliveryStats_OnlyCountsOwnDeliveries(t *testing.T) { cleanupStockTestData(t) livreurA := newTestClient(t, "stats_livreur_a") livreurB := newTestClient(t, "stats_livreur_b") client := newTestClient(t, "stats_livreur_shared_client") productID := newTestProduct(t, "StatsLivreurIsolation", 100) now := time.Now() newTestDeliveredOrder(t, livreurA, client, "approved", productID, 1, 20, 0, now) newTestDeliveredOrder(t, livreurB, client, "approved", productID, 1, 999, 0, now) c, rec := livreurStatsContext(livreurA) handlers.GetMyDeliveryStats(c) var resp deliveryStatsResponse if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil { t.Fatalf("décodage réponse: %v", err) } if resp.TodayCount != 1 || resp.TodayRevenue != 20 { t.Errorf("stats livreur A ne doivent refléter que ses propres livraisons: got count=%d revenue=%.2f want count=1 revenue=20", resp.TodayCount, resp.TodayRevenue) } }