fix(customer_service): update EnsureExternalCustomer to use TxContext

This commit is contained in:
mlogclub
2026-04-28 23:03:06 +08:00
parent 21a08f3cb1
commit 28d1cfc160
4 changed files with 44 additions and 24 deletions
+1 -1
View File
@@ -109,7 +109,7 @@ func (s *conversationService) Create(externalUser openidentity.ExternalUser, cha
var conversation *models.Conversation var conversation *models.Conversation
created := false created := false
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error { if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
customerID, err := CustomerService.EnsureExternalCustomer(ctx.Tx, externalUser) customerID, err := CustomerService.EnsureExternalCustomer(ctx, externalUser)
if err != nil { if err != nil {
return err return err
} }
+19 -7
View File
@@ -113,14 +113,17 @@ func (s *customerService) CountByCompanyIDs(companyIDs []int64) map[int64]int64
return repositories.CustomerRepository.CountByCompanyIDs(sqls.DB(), companyIDs, int(enums.StatusDeleted)) return repositories.CustomerRepository.CountByCompanyIDs(sqls.DB(), companyIDs, int(enums.StatusDeleted))
} }
func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalUser openidentity.ExternalUser) (int64, error) { func (s *customerService) EnsureExternalCustomer(ctx *sqls.TxContext, externalUser openidentity.ExternalUser) (int64, error) {
if ctx == nil || ctx.Tx == nil {
return 0, errorsx.InvalidParam("事务上下文不能为空")
}
externalSource := externalUser.ExternalSource externalSource := externalUser.ExternalSource
externalID := strings.TrimSpace(externalUser.ExternalID) externalID := strings.TrimSpace(externalUser.ExternalID)
if strings.TrimSpace(string(externalSource)) == "" || externalID == "" { if strings.TrimSpace(string(externalSource)) == "" || externalID == "" {
return 0, errorsx.Unauthorized("外部用户标识不能为空") return 0, errorsx.Unauthorized("外部用户标识不能为空")
} }
now := time.Now() now := time.Now()
if identity := repositories.CustomerIdentityRepository.GetBy(db, externalSource, externalID); identity != nil { if identity := repositories.CustomerIdentityRepository.GetBy(ctx.Tx, externalSource, externalID); identity != nil {
updates := map[string]any{ updates := map[string]any{
"last_active_at": now, "last_active_at": now,
"updated_at": now, "updated_at": now,
@@ -128,14 +131,23 @@ func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalUser openi
if strs.IsNotBlank(externalUser.ExternalName) { if strs.IsNotBlank(externalUser.ExternalName) {
updates["name"] = externalUser.ExternalName updates["name"] = externalUser.ExternalName
} }
if err := repositories.CustomerRepository.Updates(db, identity.CustomerID, updates); err != nil { if err := repositories.CustomerRepository.Updates(ctx.Tx, identity.CustomerID, updates); err != nil {
return 0, err return 0, err
} }
ctx.RegisterCallback(func() {
go func() {
if strs.IsNotBlank(externalUser.ExternalName) { if strs.IsNotBlank(externalUser.ExternalName) {
if err := s.syncConversationCustomerName(db, identity.CustomerID, externalUser.ExternalName, nil, now); err != nil { if err := s.syncConversationCustomerName(sqls.DB(), identity.CustomerID, externalUser.ExternalName, nil, now); err != nil {
return 0, err slog.Error("sync conversation customer name failed",
"customerId", identity.CustomerID,
"customerName", externalUser.ExternalName,
"error", err,
)
} }
} }
}()
})
return identity.CustomerID, nil return identity.CustomerID, nil
} }
@@ -145,10 +157,10 @@ func (s *customerService) EnsureExternalCustomer(db *gorm.DB, externalUser openi
Status: enums.StatusOk, Status: enums.StatusOk,
AuditFields: utils.BuildAuditFields(nil), AuditFields: utils.BuildAuditFields(nil),
} }
if err := repositories.CustomerRepository.Create(db, customer); err != nil { if err := repositories.CustomerRepository.Create(ctx.Tx, customer); err != nil {
return 0, err return 0, err
} }
if err := repositories.CustomerIdentityRepository.Create(db, &models.CustomerIdentity{ if err := repositories.CustomerIdentityRepository.Create(ctx.Tx, &models.CustomerIdentity{
CustomerID: customer.ID, CustomerID: customer.ID,
ExternalSource: externalSource, ExternalSource: externalSource,
ExternalID: externalID, ExternalID: externalID,
+12 -4
View File
@@ -18,12 +18,16 @@ import (
func TestEnsureExternalCustomerUpdatesNameFromExternalIdentity(t *testing.T) { func TestEnsureExternalCustomerUpdatesNameFromExternalIdentity(t *testing.T) {
db := setupCustomerServiceTestDB(t) db := setupCustomerServiceTestDB(t)
firstID, err := services.CustomerService.EnsureExternalCustomer(db, openidentity.ExternalUser{ var firstID int64
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
id, err := services.CustomerService.EnsureExternalCustomer(ctx, openidentity.ExternalUser{
ExternalSource: enums.ExternalSourceUser, ExternalSource: enums.ExternalSourceUser,
ExternalID: "user-1", ExternalID: "user-1",
ExternalName: "张三", ExternalName: "张三",
}) })
if err != nil { firstID = id
return err
}); err != nil {
t.Fatalf("EnsureExternalCustomer() first error = %v", err) t.Fatalf("EnsureExternalCustomer() first error = %v", err)
} }
@@ -37,12 +41,16 @@ func TestEnsureExternalCustomerUpdatesNameFromExternalIdentity(t *testing.T) {
t.Fatalf("create conversation error = %v", err) t.Fatalf("create conversation error = %v", err)
} }
secondID, err := services.CustomerService.EnsureExternalCustomer(db, openidentity.ExternalUser{ var secondID int64
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
id, err := services.CustomerService.EnsureExternalCustomer(ctx, openidentity.ExternalUser{
ExternalSource: enums.ExternalSourceUser, ExternalSource: enums.ExternalSourceUser,
ExternalID: "user-1", ExternalID: "user-1",
ExternalName: "李四", ExternalName: "李四",
}) })
if err != nil { secondID = id
return err
}); err != nil {
t.Fatalf("EnsureExternalCustomer() second error = %v", err) t.Fatalf("EnsureExternalCustomer() second error = %v", err)
} }
if secondID != firstID { if secondID != firstID {
@@ -57,7 +57,7 @@ func (s *customerSessionService) Exchange(channel *models.Channel, externalUser
} }
var customerID int64 var customerID int64
if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error { if err := sqls.WithTransaction(func(ctx *sqls.TxContext) error {
id, err := CustomerService.EnsureExternalCustomer(ctx.Tx, externalUser) id, err := CustomerService.EnsureExternalCustomer(ctx, externalUser)
if err != nil { if err != nil {
return err return err
} }