From a314f3f51b4718047fc8c70aaf06ee441422ecbd Mon Sep 17 00:00:00 2001 From: yml2213 Date: Tue, 8 Sep 2026 12:44:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E5=8F=91=E8=B4=A7?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E9=98=9F=E5=88=97=E4=B8=8E=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E9=80=8F=E4=BC=A0=20h5=5Fprefix=20=E5=92=8C?= =?UTF-8?q?=E5=95=86=E5=93=81=E4=BF=A1=E6=81=AF=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E4=B8=8A=E6=B8=B8=E6=8A=A5=E9=94=99=E7=BC=BA=E5=B0=91=E6=B8=A0?= =?UTF-8?q?=E9=81=93=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 上游 /public/users/orders-queue (POST/PATCH) 补充传递 h5_prefix、goods_no 和 goods_name - delivery.go submit 流程透传商品 SKU 与商品名称至队列相关方法 - 解决上游创建订单报"缺少渠道标识 h5_prefix,无法校验第三方订单状态"的故障 --- backend/internal/service/delivery.go | 13 ++++++- backend/internal/service/delivery_upstream.go | 31 ++++++++++----- backend/internal/service/merchant_test.go | 39 +++++++++++++++++++ 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/backend/internal/service/delivery.go b/backend/internal/service/delivery.go index a8c498c..a4ae2f7 100644 --- a/backend/internal/service/delivery.go +++ b/backend/internal/service/delivery.go @@ -357,7 +357,16 @@ func (s *DeliveryService) submit(orderNo, gameAccount, bindUUID string, apiClien s.markDeliverySubmissionFailed(claimed, apiClientID, deliveryStageBindMismatch, err.Error()) return nil, err } - queueOrderID, err := s.createOrderQueue(goodID, order.OrderNo) + goodsNo := "" + goodsName := "" + if info != nil && info.Product != nil { + goodsNo = info.Product.SKU + goodsName = info.Product.Name + } else if openOrder != nil && openOrder.Product != nil { + goodsNo = openOrder.Product.SKU + goodsName = openOrder.Product.Name + } + queueOrderID, err := s.createOrderQueue(goodID, order.OrderNo, goodsNo) if err != nil { s.markDeliverySubmissionFailed(claimed, apiClientID, deliveryStageCreateQueue, err.Error()) return nil, err @@ -369,7 +378,7 @@ func (s *DeliveryService) submit(orderNo, gameAccount, bindUUID string, apiClien }); err != nil { return nil, err } - if err := s.patchOrderQueue(queueOrderID, gameAccount, bindUUID); err != nil { + if err := s.patchOrderQueue(queueOrderID, gameAccount, bindUUID, goodsNo, goodsName); err != nil { s.markDeliverySubmissionFailed(claimed, apiClientID, deliveryStagePatchQueue, err.Error()) return nil, err } diff --git a/backend/internal/service/delivery_upstream.go b/backend/internal/service/delivery_upstream.go index d8fa482..4faa72d 100644 --- a/backend/internal/service/delivery_upstream.go +++ b/backend/internal/service/delivery_upstream.go @@ -44,15 +44,20 @@ func (s *DeliveryService) accountBound(bindUUID, goodID string) (map[string]inte return out.GameAccount, nil } -func (s *DeliveryService) createOrderQueue(goodID, orderNo string) (string, error) { +func (s *DeliveryService) createOrderQueue(goodID, orderNo, goodsNo string) (string, error) { var out struct { Orders []map[string]interface{} `json:"orders"` } - if err := s.signProxy("/public/users/orders-queue", "POST", map[string]interface{}{ - "good_id": goodID, - "quantity": 1, - "order_sn": orderNo, - }, &out); err != nil { + payload := map[string]interface{}{ + "good_id": goodID, + "quantity": 1, + "order_sn": orderNo, + "h5_prefix": s.channel, + } + if goodsNo != "" { + payload["goods_no"] = goodsNo + } + if err := s.signProxy("/public/users/orders-queue", "POST", payload, &out); err != nil { return "", err } if len(out.Orders) == 0 { @@ -65,13 +70,21 @@ func (s *DeliveryService) createOrderQueue(goodID, orderNo string) (string, erro return orderID, nil } -func (s *DeliveryService) patchOrderQueue(orderID, gameAccount, bindUUID string) error { +func (s *DeliveryService) patchOrderQueue(orderID, gameAccount, bindUUID, goodsNo, goodsName string) error { var out map[string]interface{} - return s.signProxy("/public/users/orders-queue", "PATCH", map[string]interface{}{ + payload := map[string]interface{}{ "order_id": orderID, "game_account": gameAccount, "bind_uuid": bindUUID, - }, &out) + "h5_prefix": s.channel, + } + if goodsNo != "" { + payload["goods_no"] = goodsNo + } + if goodsName != "" { + payload["goods_name"] = goodsName + } + return s.signProxy("/public/users/orders-queue", "PATCH", payload, &out) } func (s *DeliveryService) createUpstreamOrder(orderID, gameAccount, goodID, orderNo string) (map[string]interface{}, error) { diff --git a/backend/internal/service/merchant_test.go b/backend/internal/service/merchant_test.go index d2822b2..5819bf0 100644 --- a/backend/internal/service/merchant_test.go +++ b/backend/internal/service/merchant_test.go @@ -531,3 +531,42 @@ func TestUsernameCanBeReusedAfterMerchantAccountSoftDelete(t *testing.T) { t.Fatalf("expected a new account record, got id=%d", recreated.ID) } } + +// TestRemoveMemberDoesNotReleaseUsername 固化行为:商户侧"移除成员"只删除成员关系, +// 登录账号(含用户名)保留,同名用户名仍被占用,无法新建。 +func TestRemoveMemberDoesNotReleaseUsername(t *testing.T) { + db := newServiceTestDB(t) + merchant := model.Merchant{Code: "remove-member-keep", Name: "移除成员保留账号", Status: model.MerchantStatusActive} + actor := model.User{Username: "remove-member-actor", PasswordHash: "hash", Role: model.RoleMerchant, Status: 1} + staff := model.User{Username: "kf-2", PasswordHash: "hash", Role: model.RoleMerchant, Status: 1} + for _, entity := range []interface{}{&merchant, &actor, &staff} { + if err := db.Create(entity).Error; err != nil { + t.Fatalf("create fixture: %v", err) + } + } + if err := createDefaultMerchantRoles(db, merchant.ID); err != nil { + t.Fatalf("create default roles: %v", err) + } + + merchantSvc := NewMerchantService(db, nil, NewTenantService(db)) + member, err := merchantSvc.AddMember(merchant.ID, AddMemberInput{ + UserID: staff.ID, + Role: model.MemberRoleOperator, + }, actor.ID) + if err != nil { + t.Fatalf("add member: %v", err) + } + if err := merchantSvc.RemoveMember(merchant.ID, member.ID, actor.ID); err != nil { + t.Fatalf("remove member: %v", err) + } + + // 登录账号仍在(未被删除),用户名继续占用。 + var kept model.User + if err := db.First(&kept, staff.ID).Error; err != nil { + t.Fatalf("login account should be retained after member removal: %v", err) + } + userSvc := NewUserService(db, nil) + if _, err := userSvc.Create("kf-2", "password123", "新员工", model.RoleMerchant, 0); err == nil { + t.Fatalf("username should still be occupied after member removal") + } +}