package handler import ( "bytes" "encoding/json" "fmt" "net/http" "net/http/httptest" "github.com/gin-gonic/gin" "gorm.io/gorm" "github.com/wangjia/jiu/backend/internal/middleware" "github.com/wangjia/jiu/backend/internal/service" "github.com/wangjia/jiu/backend/testutil" ) // setupProtectedRouter 创建带 JWT 中间件的测试路由 func setupProtectedRouter(db *gorm.DB) *gin.Engine { stockSvc := service.NewStockService(db) licenseSvc := service.NewLicenseService(db) productH := NewProductHandler(db) stockInH := NewStockInHandler(db, stockSvc) stockOutH := NewStockOutHandler(db, stockSvc) inventoryH := NewInventoryHandler(db) warehouseH := NewWarehouseHandler(db) partnerH := NewPartnerHandler(db) licenseH := NewLicenseHandler(licenseSvc) r := gin.New() r.Use(gin.Recovery()) api := r.Group("/api/v1") api.Use(middleware.JWT(db)) // 商品路由 products := api.Group("/products") products.GET("", productH.List) products.POST("", productH.Create) products.GET("/:id/price-history", productH.PriceHistory) products.PUT("/:id", productH.Update) products.DELETE("/:id", productH.Delete) // 仓库路由 warehouses := api.Group("/warehouses") warehouses.GET("", warehouseH.List) warehouses.POST("", warehouseH.Create) warehouses.PUT("/:id", warehouseH.Update) warehouses.DELETE("/:id", warehouseH.Delete) // 往来单位路由 partners := api.Group("/partners") partners.GET("", partnerH.List) partners.POST("", partnerH.Create) partners.PUT("/:id", partnerH.Update) partners.DELETE("/:id", partnerH.Delete) // 入库路由 stockIn := api.Group("/stock-in") stockIn.GET("/orders", stockInH.List) stockIn.GET("/orders/:id", stockInH.Get) stockIn.POST("/orders", stockInH.Create) stockIn.PUT("/orders/:id", stockInH.Update) stockIn.PUT("/orders/:id/submit", stockInH.Submit) stockIn.PUT("/orders/:id/approve", stockInH.Approve) stockIn.PUT("/orders/:id/reject", stockInH.Reject) stockIn.PUT("/orders/:id/withdraw", stockInH.Withdraw) stockIn.POST("/orders/:id/return", stockInH.Return) stockIn.POST("/orders/:id/confirm-cost", stockInH.ConfirmCost) // 出库路由 stockOut := api.Group("/stock-out") stockOut.GET("/orders", stockOutH.List) stockOut.GET("/orders/:id", stockOutH.Get) stockOut.POST("/orders", stockOutH.Create) stockOut.PUT("/orders/:id", stockOutH.Update) stockOut.PUT("/orders/:id/submit", stockOutH.Submit) stockOut.PUT("/orders/:id/approve", stockOutH.Approve) stockOut.PUT("/orders/:id/reject", stockOutH.Reject) stockOut.PUT("/orders/:id/withdraw", stockOutH.Withdraw) stockOut.POST("/orders/:id/return", stockOutH.Return) // 库存路由 inv := api.Group("/inventory") inv.GET("", inventoryH.List) inv.GET("/logs", inventoryH.Logs) inv.POST("/checks", inventoryH.CreateCheck) inv.GET("/checks/:id", inventoryH.GetCheck) // 许可证路由 license := api.Group("/license") license.POST("/activate", licenseH.Activate) license.GET("/verify", licenseH.Verify) license.POST("/deactivate", licenseH.Deactivate) return r } // makeRequest 发起带认证的请求 func makeRequest(r *gin.Engine, method, path, token string, body interface{}) *httptest.ResponseRecorder { var bodyBytes []byte if body != nil { bodyBytes, _ = json.Marshal(body) } w := httptest.NewRecorder() req, _ := http.NewRequest(method, path, bytes.NewBuffer(bodyBytes)) req.Header.Set("Content-Type", "application/json") if token != "" { req.Header.Set("Authorization", "Bearer "+token) } r.ServeHTTP(w, req) return w } // parseResponse 解析 JSON 响应 func parseResponse(w *httptest.ResponseRecorder) map[string]interface{} { var resp map[string]interface{} json.Unmarshal(w.Body.Bytes(), &resp) return resp } // getAuthToken 为测试用户获取 token func getAuthToken(userID, shopID uint64, role string) string { return testutil.GetAuthToken(userID, shopID, role) } // extractID 从响应 data 中提取 id func extractID(w *httptest.ResponseRecorder) uint64 { resp := parseResponse(w) if data, ok := resp["data"].(map[string]interface{}); ok { if id, ok := data["id"].(float64); ok { return uint64(id) } } return 0 } // jsonBody 快速构建 JSON body func jsonBody(kv ...interface{}) map[string]interface{} { m := map[string]interface{}{} for i := 0; i+1 < len(kv); i += 2 { key := fmt.Sprintf("%v", kv[i]) m[key] = kv[i+1] } return m }