feat(distribution): 独立分销前台商城多租户体系、货源与订单数据严格隔离
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package distribution
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -16,7 +17,14 @@ func distributionTestDB(t *testing.T) *gorm.DB {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.AutoMigrate(&model.AdminUser{}, &model.Role{}, &model.ChatConversation{}, &model.RentalOrder{}, &model.AuditLog{}, &model.PaymentMerchantConfig{}, &model.DistributionSite{}, &model.DistributionSiteMember{}, &model.DistributionRuleVersion{}, &model.DistributionOrderFinancial{}, &model.DistributionOrderParty{}, &model.DistributionSiteAccount{}, &model.DistributionSitePaymentChannel{}, &model.DistributionSettlementBatch{}, &model.DistributionSettlementItem{}); err != nil {
|
||||
if err := db.AutoMigrate(
|
||||
&model.AdminUser{}, &model.Role{}, &model.ChatConversation{}, &model.RentalOrder{},
|
||||
&model.AuditLog{}, &model.PaymentMerchantConfig{}, &model.DistributionSite{},
|
||||
&model.DistributionSiteMember{}, &model.DistributionRuleVersion{}, &model.DistributionOrderFinancial{},
|
||||
&model.DistributionOrderParty{}, &model.DistributionSiteAccount{}, &model.DistributionSitePaymentChannel{},
|
||||
&model.DistributionSettlementBatch{}, &model.DistributionSettlementItem{},
|
||||
&model.RentalListing{}, &model.GameAccount{},
|
||||
); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return db
|
||||
@@ -177,3 +185,208 @@ func TestScopeSiteIDRestrictsBoundMember(t *testing.T) {
|
||||
t.Fatalf("UpdateAccountDisplay cross-site err = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncSiteAccountsAndPublicListings(t *testing.T) {
|
||||
db := distributionTestDB(t)
|
||||
repo := NewRepository(db)
|
||||
|
||||
site := model.DistributionSite{
|
||||
SiteCode: "sync_demo",
|
||||
SiteName: "同步演示站",
|
||||
Domain: "sync.example.com",
|
||||
DisplayAccountEnabled: true,
|
||||
Status: "active",
|
||||
}
|
||||
if err := db.Create(&site).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
account1 := model.GameAccount{
|
||||
Title: "三角洲极品金枪号",
|
||||
GameName: "delta_force",
|
||||
ServerRegion: "微信区",
|
||||
LoginPlatform: "PC",
|
||||
RankLevel: "王者",
|
||||
HafCoinAmount: 500000,
|
||||
Status: "active",
|
||||
}
|
||||
if err := db.Create(&account1).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
listing1 := model.RentalListing{
|
||||
ListingNo: "L10001",
|
||||
AccountID: account1.ID,
|
||||
OwnerID: 1,
|
||||
PriceCent: 2500,
|
||||
DepositAmountCent: 10000,
|
||||
Status: "published",
|
||||
ReviewStatus: "approved",
|
||||
InTransaction: false,
|
||||
}
|
||||
if err := db.Create(&listing1).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 草稿状态的商品不应该被同步
|
||||
listingDraft := model.RentalListing{
|
||||
ListingNo: "L10002",
|
||||
AccountID: 999,
|
||||
OwnerID: 1,
|
||||
PriceCent: 3000,
|
||||
DepositAmountCent: 5000,
|
||||
Status: "draft",
|
||||
ReviewStatus: "pending",
|
||||
}
|
||||
if err := db.Create(&listingDraft).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 首次同步:应当成功新增 1 条,跳过 0 条
|
||||
res1, err := repo.SyncSiteAccounts(t.Context(), 0, site.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("SyncSiteAccounts err = %v", err)
|
||||
}
|
||||
if res1.SyncedCount != 1 || res1.SkippedCount != 0 || res1.TotalActive != 1 {
|
||||
t.Fatalf("unexpected res1: %+v", res1)
|
||||
}
|
||||
|
||||
// 再次同步:幂等保证,跳过 1 条,新增 0 条
|
||||
res2, err := repo.SyncSiteAccounts(t.Context(), 0, site.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("SyncSiteAccounts retry err = %v", err)
|
||||
}
|
||||
if res2.SyncedCount != 0 || res2.SkippedCount != 1 || res2.TotalActive != 1 {
|
||||
t.Fatalf("unexpected res2: %+v", res2)
|
||||
}
|
||||
|
||||
// 验证管理后台列表查询携带丰富字段
|
||||
displays, err := repo.ListAccountDisplays(t.Context(), site.ID, "")
|
||||
if err != nil {
|
||||
t.Fatalf("ListAccountDisplays err = %v", err)
|
||||
}
|
||||
if len(displays) != 1 {
|
||||
t.Fatalf("expected 1 display, got %d", len(displays))
|
||||
}
|
||||
d := displays[0]
|
||||
if d.Title != "三角洲极品金枪号" || d.GameName != "delta_force" || d.PriceCent != 2500 || d.DepositAmountCent != 10000 || d.ListingNo != "L10001" {
|
||||
t.Fatalf("unexpected enriched display: %+v", d)
|
||||
}
|
||||
|
||||
// 验证公共端点浏览查询
|
||||
pubList, err := repo.ListPublicSiteListings(t.Context(), site.SiteCode, 1, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("ListPublicSiteListings err = %v", err)
|
||||
}
|
||||
if pubList.Total != 1 || len(pubList.Items) != 1 {
|
||||
t.Fatalf("expected 1 public item, got %+v", pubList)
|
||||
}
|
||||
if pubList.Items[0].Title != "三角洲极品金枪号" || pubList.Items[0].SiteCode != site.SiteCode {
|
||||
t.Fatalf("unexpected public item: %+v", pubList.Items[0])
|
||||
}
|
||||
|
||||
// 下架该展示账号后,公共端点不再返回
|
||||
if _, err := repo.UpdateAccountDisplay(t.Context(), 0, d.ID, "disabled"); err != nil {
|
||||
t.Fatalf("UpdateAccountDisplay disabled err = %v", err)
|
||||
}
|
||||
pubList2, err := repo.ListPublicSiteListings(t.Context(), site.SiteCode, 1, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("ListPublicSiteListings after disabled err = %v", err)
|
||||
}
|
||||
if pubList2.Total != 0 || len(pubList2.Items) != 0 {
|
||||
t.Fatalf("expected 0 public items after disabled, got %+v", pubList2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOnboardSiteAutoSyncsActiveListings(t *testing.T) {
|
||||
db := distributionTestDB(t)
|
||||
repo := NewRepository(db)
|
||||
|
||||
account := model.GameAccount{
|
||||
Title: "王者荣耀国服账号",
|
||||
GameName: "honor_of_kings",
|
||||
ServerRegion: "手Q一区",
|
||||
LoginPlatform: "iOS",
|
||||
Status: "active",
|
||||
}
|
||||
if err := db.Create(&account).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
listing := model.RentalListing{
|
||||
ListingNo: "L20001",
|
||||
AccountID: account.ID,
|
||||
OwnerID: 2,
|
||||
PriceCent: 5000,
|
||||
Status: "published",
|
||||
ReviewStatus: "approved",
|
||||
}
|
||||
if err := db.Create(&listing).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dispEnabled := true
|
||||
onboardResp, err := repo.OnboardSite(t.Context(), OnboardSiteRequest{
|
||||
SiteCode: "auto_sync_site",
|
||||
SiteName: "自动同步站点",
|
||||
Domain: "auto.example.com",
|
||||
AdminUsername: "auto_admin",
|
||||
AdminPassword: "securepass123",
|
||||
DisplayAccountEnabled: &dispEnabled,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("OnboardSite err = %v", err)
|
||||
}
|
||||
|
||||
displays, err := repo.ListAccountDisplays(t.Context(), onboardResp.Site.ID, "")
|
||||
if err != nil {
|
||||
t.Fatalf("ListAccountDisplays err = %v", err)
|
||||
}
|
||||
if len(displays) != 1 {
|
||||
t.Fatalf("expected 1 auto-synced account, got %d", len(displays))
|
||||
}
|
||||
if displays[0].Title != "王者荣耀国服账号" || displays[0].ListingNo != "L20001" {
|
||||
t.Fatalf("unexpected auto-synced display: %+v", displays[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPublicSiteInfo(t *testing.T) {
|
||||
db := distributionTestDB(t)
|
||||
repo := NewRepository(db)
|
||||
|
||||
site := model.DistributionSite{
|
||||
SiteCode: "info_site",
|
||||
SiteName: "信息测试站",
|
||||
Domain: "info.example.com",
|
||||
Status: "active",
|
||||
DisplayAccountEnabled: true,
|
||||
}
|
||||
if err := db.Create(&site).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Query by code
|
||||
info, err := repo.GetPublicSiteInfo(t.Context(), "info_site", "")
|
||||
if err != nil {
|
||||
t.Fatalf("GetPublicSiteInfo by code failed: %v", err)
|
||||
}
|
||||
if info.SiteName != "信息测试站" || info.SiteCode != "info_site" {
|
||||
t.Fatalf("unexpected info: %+v", info)
|
||||
}
|
||||
|
||||
// Query by domain
|
||||
infoByDomain, err := repo.GetPublicSiteInfo(t.Context(), "", "info.example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("GetPublicSiteInfo by domain failed: %v", err)
|
||||
}
|
||||
if infoByDomain.SiteName != "信息测试站" {
|
||||
t.Fatalf("unexpected info by domain: %+v", infoByDomain)
|
||||
}
|
||||
|
||||
// Query not found
|
||||
_, err = repo.GetPublicSiteInfo(t.Context(), "not_found", "")
|
||||
if !errors.Is(err, ErrSiteNotFound) {
|
||||
t.Fatalf("expected ErrSiteNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user