package handler import ( "fmt" "net/http" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/wangjia/jiu/backend/testutil" ) func TestPartnerHandler_CRUD(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "PT001") user := testutil.CreateTestUser(db, shop.ID, "admin", "pass", "admin") token := getAuthToken(user.ID, shop.ID, "admin") r := setupProtectedRouter(db) // 1. Create supplier w := makeRequest(r, "POST", "/api/v1/partners", token, map[string]interface{}{ "name": "Test Supplier", "type": "supplier", "code": "SUP001", }) require.Equal(t, http.StatusCreated, w.Code) partnerID := extractID(w) assert.NotZero(t, partnerID) data := parseResponse(w)["data"].(map[string]interface{}) assert.Equal(t, "Test Supplier", data["name"]) assert.Equal(t, "supplier", data["type"]) // 2. List w = makeRequest(r, "GET", "/api/v1/partners", token, nil) assert.Equal(t, http.StatusOK, w.Code) resp := parseResponse(w) assert.Equal(t, float64(1), resp["total"].(float64)) // 3. Update w = makeRequest(r, "PUT", fmt.Sprintf("/api/v1/partners/%d", partnerID), token, map[string]interface{}{ "name": "Updated Supplier", "type": "supplier", }) assert.Equal(t, http.StatusOK, w.Code) updatedData := parseResponse(w)["data"].(map[string]interface{}) assert.Equal(t, "Updated Supplier", updatedData["name"]) // 4. Delete w = makeRequest(r, "DELETE", fmt.Sprintf("/api/v1/partners/%d", partnerID), token, nil) assert.Equal(t, http.StatusOK, w.Code) // 5. List after delete - should be 0 w = makeRequest(r, "GET", "/api/v1/partners", token, nil) resp = parseResponse(w) assert.Equal(t, float64(0), resp["total"].(float64)) } func TestPartnerHandler_NoAuth(t *testing.T) { db := testutil.SetupTestDB() r := setupProtectedRouter(db) w := makeRequest(r, "GET", "/api/v1/partners", "", nil) assert.Equal(t, http.StatusUnauthorized, w.Code) } func TestPartnerHandler_HotelIsolation(t *testing.T) { db := testutil.SetupTestDB() shopA := testutil.CreateTestShop(db, "PT_A") userA := testutil.CreateTestUser(db, shopA.ID, "adminA", "pass", "admin") tokenA := getAuthToken(userA.ID, shopA.ID, "admin") shopB := testutil.CreateTestShop(db, "PT_B") userB := testutil.CreateTestUser(db, shopB.ID, "adminB", "pass", "admin") tokenB := getAuthToken(userB.ID, shopB.ID, "admin") r := setupProtectedRouter(db) // 门店 A 创建往来单位 w := makeRequest(r, "POST", "/api/v1/partners", tokenA, map[string]interface{}{ "name": "A Supplier", "type": "supplier", }) require.Equal(t, http.StatusCreated, w.Code) partnerAID := extractID(w) // 门店 B 创建往来单位 makeRequest(r, "POST", "/api/v1/partners", tokenB, map[string]interface{}{ "name": "B Customer", "type": "customer", }) // 门店 A 只能看到自己的数据 w = makeRequest(r, "GET", "/api/v1/partners", tokenA, nil) resp := parseResponse(w) assert.Equal(t, float64(1), resp["total"].(float64)) listData := resp["data"].([]interface{}) assert.Equal(t, "A Supplier", listData[0].(map[string]interface{})["name"]) // 门店 B 只能看到自己的数据 w = makeRequest(r, "GET", "/api/v1/partners", tokenB, nil) respB := parseResponse(w) assert.Equal(t, float64(1), respB["total"].(float64)) // 门店 B 不能修改门店 A 的往来单位 w = makeRequest(r, "PUT", fmt.Sprintf("/api/v1/partners/%d", partnerAID), tokenB, map[string]interface{}{ "name": "Hacked", "type": "supplier", }) assert.Equal(t, http.StatusNotFound, w.Code) // 门店 B 不能删除门店 A 的往来单位 w = makeRequest(r, "DELETE", fmt.Sprintf("/api/v1/partners/%d", partnerAID), tokenB, nil) assert.Equal(t, http.StatusNotFound, w.Code) } func TestPartnerHandler_UpdateNotFound(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "PT002") user := testutil.CreateTestUser(db, shop.ID, "admin", "pass", "admin") token := getAuthToken(user.ID, shop.ID, "admin") r := setupProtectedRouter(db) w := makeRequest(r, "PUT", "/api/v1/partners/99999", token, map[string]interface{}{ "name": "Nonexistent", "type": "supplier", }) assert.Equal(t, http.StatusNotFound, w.Code) } func TestPartnerHandler_DeleteNotFound(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "PT003") user := testutil.CreateTestUser(db, shop.ID, "admin", "pass", "admin") token := getAuthToken(user.ID, shop.ID, "admin") r := setupProtectedRouter(db) w := makeRequest(r, "DELETE", "/api/v1/partners/99999", token, nil) assert.Equal(t, http.StatusNotFound, w.Code) } func TestPartnerHandler_Create_MissingName(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "PT004") user := testutil.CreateTestUser(db, shop.ID, "admin", "pass", "admin") token := getAuthToken(user.ID, shop.ID, "admin") r := setupProtectedRouter(db) // 缺少 name 字段(必填) w := makeRequest(r, "POST", "/api/v1/partners", token, map[string]interface{}{ "type": "supplier", }) assert.Equal(t, http.StatusBadRequest, w.Code) } func TestPartnerHandler_List_FilterByType(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "PT005") user := testutil.CreateTestUser(db, shop.ID, "admin", "pass", "admin") token := getAuthToken(user.ID, shop.ID, "admin") r := setupProtectedRouter(db) // 创建供应商和客户 makeRequest(r, "POST", "/api/v1/partners", token, map[string]interface{}{ "name": "Supplier One", "type": "supplier", }) makeRequest(r, "POST", "/api/v1/partners", token, map[string]interface{}{ "name": "Customer One", "type": "customer", }) // 列出全部 w := makeRequest(r, "GET", "/api/v1/partners", token, nil) resp := parseResponse(w) assert.Equal(t, float64(2), resp["total"].(float64)) } func TestPartnerHandler_List_KeywordSearch(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "PT006") user := testutil.CreateTestUser(db, shop.ID, "admin", "pass", "admin") token := getAuthToken(user.ID, shop.ID, "admin") r := setupProtectedRouter(db) makeRequest(r, "POST", "/api/v1/partners", token, map[string]interface{}{ "name": "Beijing Beer Co", "type": "supplier", "phone": "13800001111", }) makeRequest(r, "POST", "/api/v1/partners", token, map[string]interface{}{ "name": "Shanghai Wine Ltd", "type": "supplier", }) // 按名称搜索 w := makeRequest(r, "GET", "/api/v1/partners?keyword=Beijing", token, nil) resp := parseResponse(w) assert.Equal(t, float64(1), resp["total"].(float64)) // 搜索不存在的关键词 w = makeRequest(r, "GET", "/api/v1/partners?keyword=Nonexistent", token, nil) resp = parseResponse(w) assert.Equal(t, float64(0), resp["total"].(float64)) } func TestPartnerHandler_ShopIDFromToken(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "PT007") user := testutil.CreateTestUser(db, shop.ID, "admin", "pass", "admin") token := getAuthToken(user.ID, shop.ID, "admin") r := setupProtectedRouter(db) // 在请求体中尝试传入不同的 shop_id w := makeRequest(r, "POST", "/api/v1/partners", token, map[string]interface{}{ "name": "Test Partner", "type": "supplier", "shop_id": 9999, }) require.Equal(t, http.StatusCreated, w.Code) data := parseResponse(w)["data"].(map[string]interface{}) // shop_id 应该来自 token createdShopID := uint64(data["shop_id"].(float64)) assert.Equal(t, shop.ID, createdShopID) }