feat(crm): complete contact label avatar gaps

This commit is contained in:
2026-06-05 02:53:24 +08:00
parent 5cf735076d
commit 7a033e28a0
16 changed files with 512 additions and 31 deletions
@@ -12,6 +12,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"gorm.io/datatypes"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
@@ -103,6 +104,8 @@ func (s *CompanyHandlerTestSuite) SetupSuite() {
companies.PUT("/:company_id", s.handler.Update)
companies.PATCH("/:company_id", s.handler.Update)
companies.DELETE("/:company_id", s.handler.Delete)
companies.POST("/:company_id/destroy_custom_attributes", s.handler.DestroyCustomAttributes)
companies.DELETE("/:company_id/avatar", s.handler.DeleteAvatar)
companies.GET("/:company_id/contacts", s.handler.ListContacts)
companies.GET("/:company_id/contacts/search", s.handler.SearchContacts)
companies.POST("/:company_id/contacts", s.handler.AddContact)
@@ -292,6 +295,55 @@ func (s *CompanyHandlerTestSuite) TestDelete_InvalidID() {
"Expected 400 or 404 for invalid company ID, got %d", w.Code)
}
func (s *CompanyHandlerTestSuite) TestDestroyCustomAttributes_Success() {
companyRepo := repository.NewCompanyRepo(s.db)
company := &model.Company{
AccountID: s.accountID,
Name: "AttrCorp",
CustomAttributes: datatypes.JSON([]byte(`{"plan":"pro","tier":"gold"}`)),
}
s.Require().NoError(companyRepo.Create(context.Background(), company))
w := s.makeRequest("POST", fmt.Sprintf("/api/v1/accounts/%d/companies/%d/destroy_custom_attributes", s.accountID, company.ID), map[string]interface{}{
"custom_attributes": []string{"tier"},
})
assert.Equal(s.T(), http.StatusOK, w.Code)
var resp map[string]interface{}
s.Require().NoError(json.Unmarshal(w.Body.Bytes(), &resp))
payload := resp["payload"].(map[string]interface{})
attrs := payload["custom_attributes"].(map[string]interface{})
assert.Equal(s.T(), "pro", attrs["plan"])
assert.NotContains(s.T(), attrs, "tier")
}
func (s *CompanyHandlerTestSuite) TestDestroyCustomAttributes_RequiresArray() {
companyRepo := repository.NewCompanyRepo(s.db)
company := &model.Company{AccountID: s.accountID, Name: "AttrInvalidCorp"}
s.Require().NoError(companyRepo.Create(context.Background(), company))
w := s.makeRequest("POST", fmt.Sprintf("/api/v1/accounts/%d/companies/%d/destroy_custom_attributes", s.accountID, company.ID), map[string]interface{}{})
assert.Equal(s.T(), http.StatusUnprocessableEntity, w.Code)
}
func (s *CompanyHandlerTestSuite) TestDeleteAvatar_Success() {
companyRepo := repository.NewCompanyRepo(s.db)
company := &model.Company{AccountID: s.accountID, Name: "AvatarCorp", FaviconURL: "https://example.com/avatar.png"}
s.Require().NoError(companyRepo.Create(context.Background(), company))
w := s.makeRequest("DELETE", fmt.Sprintf("/api/v1/accounts/%d/companies/%d/avatar", s.accountID, company.ID), nil)
assert.Equal(s.T(), http.StatusOK, w.Code)
var resp map[string]interface{}
s.Require().NoError(json.Unmarshal(w.Body.Bytes(), &resp))
payload := resp["payload"].(map[string]interface{})
assert.Equal(s.T(), "", payload["avatar_url"])
var found model.Company
s.Require().NoError(s.db.First(&found, company.ID).Error)
assert.Equal(s.T(), "", found.FaviconURL)
}
// ========== ListContacts ==========
func (s *CompanyHandlerTestSuite) TestListContacts_Success() {