feat(ticket): add customer linking functionality to tickets
This commit is contained in:
@@ -168,6 +168,21 @@ func (c *TicketController) PostUpdate() *web.JsonResult {
|
||||
return web.JsonSuccess()
|
||||
}
|
||||
|
||||
func (c *TicketController) PostLink_customer() *web.JsonResult {
|
||||
operator, err := services.AuthService.RequirePermission(c.Ctx, constants.PermissionTicketUpdate)
|
||||
if err != nil {
|
||||
return web.JsonError(err)
|
||||
}
|
||||
req := request.LinkTicketCustomerRequest{}
|
||||
if err := params.ReadJSON(c.Ctx, &req); err != nil {
|
||||
return web.JsonError(err)
|
||||
}
|
||||
if err := services.TicketService.LinkCustomer(req.TicketID, req.CustomerID, operator); err != nil {
|
||||
return web.JsonError(err)
|
||||
}
|
||||
return web.JsonSuccess()
|
||||
}
|
||||
|
||||
func (c *TicketController) PostAssign() *web.JsonResult {
|
||||
operator, err := services.AuthService.RequirePermission(c.Ctx, constants.PermissionTicketAssign)
|
||||
if err != nil {
|
||||
|
||||
@@ -27,6 +27,11 @@ type UpdateTicketRequest struct {
|
||||
CurrentAssigneeID int64 `json:"currentAssigneeId"`
|
||||
}
|
||||
|
||||
type LinkTicketCustomerRequest struct {
|
||||
TicketID int64 `json:"ticketId"`
|
||||
CustomerID int64 `json:"customerId"`
|
||||
}
|
||||
|
||||
type AssignTicketRequest struct {
|
||||
TicketID int64 `json:"ticketId"`
|
||||
ToUserID int64 `json:"toUserId"`
|
||||
|
||||
@@ -230,8 +230,8 @@ func (s *ticketService) CreateTicket(req request.CreateTicketRequest, operator *
|
||||
|
||||
func withSQLiteTicketCreateLock(db *gorm.DB, fn func() error) error {
|
||||
if db != nil && db.Dialector.Name() == "sqlite" {
|
||||
ticketNoSQLiteMu.Lock()
|
||||
defer ticketNoSQLiteMu.Unlock()
|
||||
TicketNoSequenceService.ticketNoSQLiteMu.Lock()
|
||||
defer TicketNoSequenceService.ticketNoSQLiteMu.Unlock()
|
||||
}
|
||||
return fn()
|
||||
}
|
||||
@@ -309,6 +309,35 @@ func (s *ticketService) UpdateTicket(req request.UpdateTicketRequest, operator *
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ticketService) LinkCustomer(ticketID int64, customerID int64, operator *dto.AuthPrincipal) error {
|
||||
if operator == nil {
|
||||
return errorsx.Unauthorized("未登录或登录已过期")
|
||||
}
|
||||
ticket := s.Get(ticketID)
|
||||
if ticket == nil {
|
||||
return errorsx.InvalidParam("工单不存在")
|
||||
}
|
||||
if customerID <= 0 || CustomerService.Get(customerID) == nil {
|
||||
return errorsx.InvalidParam("客户不存在")
|
||||
}
|
||||
if ticket.ConversationID > 0 {
|
||||
conversation := ConversationService.Get(ticket.ConversationID)
|
||||
if conversation == nil {
|
||||
return errorsx.InvalidParam("会话不存在")
|
||||
}
|
||||
if conversation.CustomerID > 0 && conversation.CustomerID != customerID {
|
||||
return errorsx.InvalidParam("会话与客户不匹配")
|
||||
}
|
||||
}
|
||||
now := time.Now()
|
||||
return repositories.TicketRepository.Updates(sqls.DB(), ticket.ID, map[string]any{
|
||||
"customer_id": customerID,
|
||||
"updated_at": now,
|
||||
"update_user_id": operator.UserID,
|
||||
"update_user_name": operator.Username,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ticketService) AssignTicket(req request.AssignTicketRequest, operator *dto.AuthPrincipal) error {
|
||||
if operator == nil {
|
||||
return errorsx.Unauthorized("未登录或登录已过期")
|
||||
|
||||
@@ -119,6 +119,44 @@ func TestTicketServiceCreateTicketPublishesTicketCreatedEvent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTicketServiceLinkCustomerUpdatesTicketCustomerID(t *testing.T) {
|
||||
setupTicketTestDB(t)
|
||||
operator := createTestOperator(t, "link-ticket-customer")
|
||||
customerID := createTestCustomer(t, "link-ticket-customer")
|
||||
ticket, err := services.TicketService.CreateTicket(createTestTicketRequest("link-ticket-customer"), operator)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateTicket() error = %v", err)
|
||||
}
|
||||
if ticket.CustomerID != 0 {
|
||||
t.Fatalf("expected ticket without customer, got %d", ticket.CustomerID)
|
||||
}
|
||||
|
||||
if err := services.TicketService.LinkCustomer(ticket.ID, customerID, operator); err != nil {
|
||||
t.Fatalf("LinkCustomer() error = %v", err)
|
||||
}
|
||||
|
||||
updated := services.TicketService.Get(ticket.ID)
|
||||
if updated == nil {
|
||||
t.Fatalf("expected ticket")
|
||||
}
|
||||
if updated.CustomerID != customerID {
|
||||
t.Fatalf("expected customer id %d, got %d", customerID, updated.CustomerID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTicketServiceLinkCustomerRejectsMissingCustomer(t *testing.T) {
|
||||
setupTicketTestDB(t)
|
||||
operator := createTestOperator(t, "link-ticket-missing-customer")
|
||||
ticket, err := services.TicketService.CreateTicket(createTestTicketRequest("link-ticket-missing-customer"), operator)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateTicket() error = %v", err)
|
||||
}
|
||||
|
||||
if err := services.TicketService.LinkCustomer(ticket.ID, 999999, operator); err == nil {
|
||||
t.Fatalf("expected LinkCustomer() to reject missing customer")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTicketServiceChangeStatusSetsHandledAt(t *testing.T) {
|
||||
setupTicketTestDB(t)
|
||||
operator := createTestOperator(t, "status-operator")
|
||||
|
||||
Reference in New Issue
Block a user