feat(distribution): 分站可下调收号比例且不超过主站上限
让分销站能按自身能力下调收号比例扩大利润,同时把主站回收比例作为硬边界,避免分站把比例加得比主站更高。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -16,6 +16,7 @@ type SiteDTO struct {
|
||||
FooterInfoJSON string `json:"footer_info_json"`
|
||||
DefaultSupportGroupID *uint64 `json:"default_support_group_id,omitempty"`
|
||||
ListingQrcodeURL string `json:"listing_qrcode_url"`
|
||||
ReceiveRatioDelta float64 `json:"receive_ratio_delta"`
|
||||
TaxEnabled bool `json:"tax_enabled"`
|
||||
TaxRateBPS int64 `json:"tax_rate_bps"`
|
||||
SettlementHoldDays int `json:"settlement_hold_days"`
|
||||
@@ -24,32 +25,34 @@ type SiteDTO struct {
|
||||
}
|
||||
|
||||
type CreateSiteRequest struct {
|
||||
SiteCode string `json:"site_code" binding:"required,max=64"`
|
||||
SiteName string `json:"site_name" binding:"required,max=128"`
|
||||
Domain string `json:"domain" binding:"required,max=255"`
|
||||
DisplayAccountEnabled *bool `json:"display_account_enabled"`
|
||||
DefaultSupportGroupID *uint64 `json:"default_support_group_id"`
|
||||
ListingQrcodeURL *string `json:"listing_qrcode_url"`
|
||||
TaxEnabled *bool `json:"tax_enabled"`
|
||||
TaxRateBPS *int64 `json:"tax_rate_bps"`
|
||||
SettlementHoldDays *int `json:"settlement_hold_days"`
|
||||
SiteCode string `json:"site_code" binding:"required,max=64"`
|
||||
SiteName string `json:"site_name" binding:"required,max=128"`
|
||||
Domain string `json:"domain" binding:"required,max=255"`
|
||||
DisplayAccountEnabled *bool `json:"display_account_enabled"`
|
||||
DefaultSupportGroupID *uint64 `json:"default_support_group_id"`
|
||||
ListingQrcodeURL *string `json:"listing_qrcode_url"`
|
||||
ReceiveRatioDelta *float64 `json:"receive_ratio_delta"`
|
||||
TaxEnabled *bool `json:"tax_enabled"`
|
||||
TaxRateBPS *int64 `json:"tax_rate_bps"`
|
||||
SettlementHoldDays *int `json:"settlement_hold_days"`
|
||||
}
|
||||
|
||||
type UpdateSiteRequest struct {
|
||||
SiteName *string `json:"site_name"`
|
||||
Domain *string `json:"domain"`
|
||||
Status *string `json:"status"`
|
||||
DisplayAccountEnabled *bool `json:"display_account_enabled"`
|
||||
DefaultSupportGroupID *uint64 `json:"default_support_group_id"`
|
||||
ListingQrcodeURL *string `json:"listing_qrcode_url"`
|
||||
TaxEnabled *bool `json:"tax_enabled"`
|
||||
TaxRateBPS *int64 `json:"tax_rate_bps"`
|
||||
SettlementHoldDays *int `json:"settlement_hold_days"`
|
||||
LogoURL *string `json:"logo_url"`
|
||||
FaviconURL *string `json:"favicon_url"`
|
||||
BannersJSON *string `json:"banners_json"`
|
||||
AnnouncementsJSON *string `json:"announcements_json"`
|
||||
FooterInfoJSON *string `json:"footer_info_json"`
|
||||
SiteName *string `json:"site_name"`
|
||||
Domain *string `json:"domain"`
|
||||
Status *string `json:"status"`
|
||||
DisplayAccountEnabled *bool `json:"display_account_enabled"`
|
||||
DefaultSupportGroupID *uint64 `json:"default_support_group_id"`
|
||||
ListingQrcodeURL *string `json:"listing_qrcode_url"`
|
||||
ReceiveRatioDelta *float64 `json:"receive_ratio_delta"`
|
||||
TaxEnabled *bool `json:"tax_enabled"`
|
||||
TaxRateBPS *int64 `json:"tax_rate_bps"`
|
||||
SettlementHoldDays *int `json:"settlement_hold_days"`
|
||||
LogoURL *string `json:"logo_url"`
|
||||
FaviconURL *string `json:"favicon_url"`
|
||||
BannersJSON *string `json:"banners_json"`
|
||||
AnnouncementsJSON *string `json:"announcements_json"`
|
||||
FooterInfoJSON *string `json:"footer_info_json"`
|
||||
}
|
||||
|
||||
type RuleDTO struct {
|
||||
@@ -244,6 +247,7 @@ type PublicSiteInfoDTO struct {
|
||||
AnnouncementsJSON string `json:"announcements_json"`
|
||||
FooterInfoJSON string `json:"footer_info_json"`
|
||||
DefaultSupportGroupID *uint64 `json:"default_support_group_id,omitempty"`
|
||||
ReceiveRatioDelta float64 `json:"receive_ratio_delta"`
|
||||
}
|
||||
|
||||
type UpdateAccountDisplayRequest struct {
|
||||
@@ -353,26 +357,29 @@ type OnboardSiteResponse struct {
|
||||
|
||||
// ReceivedListingDTO 是分销站点收到的账号资产信息
|
||||
type ReceivedListingDTO struct {
|
||||
ListingID uint64 `json:"listing_id"`
|
||||
ListingNo string `json:"listing_no"`
|
||||
SiteID uint64 `json:"site_id"`
|
||||
AccountID uint64 `json:"account_id"`
|
||||
OwnerID uint64 `json:"owner_id"`
|
||||
OwnerPhone string `json:"owner_phone"`
|
||||
OwnerNickname string `json:"owner_nickname"`
|
||||
Title string `json:"title"`
|
||||
GameName string `json:"game_name"`
|
||||
ServerRegion string `json:"server_region"`
|
||||
LoginPlatform string `json:"login_platform"`
|
||||
RankLevel string `json:"rank_level"`
|
||||
HafCoinAmount int64 `json:"haf_coin_amount"`
|
||||
PriceCent int64 `json:"price_cent"`
|
||||
DepositAmountCent int64 `json:"deposit_amount_cent"`
|
||||
Status string `json:"status"`
|
||||
ReviewStatus string `json:"review_status"`
|
||||
ReviewReason string `json:"review_reason"`
|
||||
PublishedAt *time.Time `json:"published_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ListingID uint64 `json:"listing_id"`
|
||||
ListingNo string `json:"listing_no"`
|
||||
SiteID uint64 `json:"site_id"`
|
||||
AccountID uint64 `json:"account_id"`
|
||||
OwnerID uint64 `json:"owner_id"`
|
||||
OwnerPhone string `json:"owner_phone"`
|
||||
OwnerNickname string `json:"owner_nickname"`
|
||||
Title string `json:"title"`
|
||||
GameName string `json:"game_name"`
|
||||
ServerRegion string `json:"server_region"`
|
||||
LoginPlatform string `json:"login_platform"`
|
||||
RankLevel string `json:"rank_level"`
|
||||
HafCoinAmount int64 `json:"haf_coin_amount"`
|
||||
SellerRatio float64 `json:"seller_ratio"`
|
||||
SellerTotalPriceCent int64 `json:"seller_total_price_cent"`
|
||||
BuyerRatio float64 `json:"buyer_ratio"`
|
||||
PriceCent int64 `json:"price_cent"`
|
||||
DepositAmountCent int64 `json:"deposit_amount_cent"`
|
||||
Status string `json:"status"`
|
||||
ReviewStatus string `json:"review_status"`
|
||||
ReviewReason string `json:"review_reason"`
|
||||
PublishedAt *time.Time `json:"published_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type ReceivedListingQuery struct {
|
||||
|
||||
@@ -68,6 +68,7 @@ func setupHandlerTestEnv(t *testing.T) *handlerTestEnv {
|
||||
siteProtected.POST("/sites/:id/withdrawals", h.ApplySiteWithdrawal)
|
||||
siteProtected.GET("/sites/:id/withdrawals", h.ListSiteWithdrawals)
|
||||
siteProtected.GET("/sites/:id/analytics", h.GetDashboardAnalytics)
|
||||
siteProtected.PUT("/sites/:id", h.UpdateSite)
|
||||
siteProtected.PUT("/sites/:id/branding", h.UpdateSiteBranding)
|
||||
siteProtected.POST("/sites/:id/sync-accounts", h.SyncSiteAccounts)
|
||||
siteProtected.GET("/received-listings", h.ListReceivedListings)
|
||||
@@ -404,6 +405,33 @@ func TestHandler_SiteOperatorEndpoints(t *testing.T) {
|
||||
t.Fatalf("branding expected 200, got %d: %s", wBrand.Code, wBrand.Body.String())
|
||||
}
|
||||
|
||||
delta := 2.5
|
||||
wRatio := env.request("PUT", fmt.Sprintf("/api/v1/distribution/sites/%d", siteA.ID), UpdateSiteRequest{ReceiveRatioDelta: &delta}, adminA.ID, nil)
|
||||
if wRatio.Code != http.StatusOK {
|
||||
t.Fatalf("receive ratio expected 200, got %d: %s", wRatio.Code, wRatio.Body.String())
|
||||
}
|
||||
var ratioResp struct {
|
||||
Code string `json:"code"`
|
||||
Data SiteDTO `json:"data"`
|
||||
}
|
||||
json.Unmarshal(wRatio.Body.Bytes(), &ratioResp)
|
||||
if ratioResp.Data.ReceiveRatioDelta != 2.5 {
|
||||
t.Fatalf("receive_ratio_delta = %v, want 2.5", ratioResp.Data.ReceiveRatioDelta)
|
||||
}
|
||||
hackedName := "越权改名"
|
||||
wHackName := env.request("PUT", fmt.Sprintf("/api/v1/distribution/sites/%d", siteA.ID), UpdateSiteRequest{SiteName: &hackedName}, adminA.ID, nil)
|
||||
if wHackName.Code != http.StatusOK {
|
||||
t.Fatalf("operator privileged field expected 200 with ignore, got %d: %s", wHackName.Code, wHackName.Body.String())
|
||||
}
|
||||
json.Unmarshal(wHackName.Body.Bytes(), &ratioResp)
|
||||
if ratioResp.Data.SiteName != siteA.SiteName {
|
||||
t.Fatalf("operator must not rename site, got %q", ratioResp.Data.SiteName)
|
||||
}
|
||||
wCrossRatio := env.request("PUT", fmt.Sprintf("/api/v1/distribution/sites/%d", siteA.ID), UpdateSiteRequest{ReceiveRatioDelta: &delta}, adminB.ID, nil)
|
||||
if wCrossRatio.Code != http.StatusForbidden {
|
||||
t.Fatalf("cross-site receive ratio expected 403, got %d: %s", wCrossRatio.Code, wCrossRatio.Body.String())
|
||||
}
|
||||
|
||||
// 6. 同步主站商品货架
|
||||
opOwner := model.User{Phone: "13800000077", Status: "active"}
|
||||
env.db.Create(&opOwner)
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
@@ -64,6 +65,13 @@ func normalizeSettlementHoldDays(days int) (int, error) {
|
||||
return days, nil
|
||||
}
|
||||
|
||||
func normalizeReceiveRatioDelta(delta float64) (float64, error) {
|
||||
if delta < 0 {
|
||||
return 0, ErrInvalidAmount
|
||||
}
|
||||
return listingpkg.NormalizeSiteReceiveRatioDelta(delta), nil
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
db *gorm.DB
|
||||
redis *redis.Client
|
||||
@@ -256,6 +264,13 @@ func (r *Repository) CreateSite(ctx context.Context, req CreateSiteRequest) (*Si
|
||||
if req.ListingQrcodeURL != nil {
|
||||
row.ListingQrcodeURL = strings.TrimSpace(*req.ListingQrcodeURL)
|
||||
}
|
||||
if req.ReceiveRatioDelta != nil {
|
||||
delta, err := normalizeReceiveRatioDelta(*req.ReceiveRatioDelta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
row.ReceiveRatioDelta = delta
|
||||
}
|
||||
if req.TaxEnabled != nil {
|
||||
row.TaxEnabled = *req.TaxEnabled
|
||||
}
|
||||
@@ -293,6 +308,27 @@ func (r *Repository) UpdateSite(ctx context.Context, adminID, id uint64, req Upd
|
||||
if err := r.ensureSiteAccessWithDB(ctx, tx, adminID, row.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
globalAccess := adminID == 0
|
||||
if !globalAccess {
|
||||
global, accessErr := r.hasGlobalDistributionAccessWithDB(ctx, tx, adminID)
|
||||
if accessErr != nil {
|
||||
return accessErr
|
||||
}
|
||||
globalAccess = global
|
||||
}
|
||||
if req.ReceiveRatioDelta != nil {
|
||||
delta, err := normalizeReceiveRatioDelta(*req.ReceiveRatioDelta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
row.ReceiveRatioDelta = delta
|
||||
}
|
||||
if !globalAccess {
|
||||
if err := tx.Save(&row).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if req.SiteName != nil {
|
||||
row.SiteName = strings.TrimSpace(*req.SiteName)
|
||||
}
|
||||
@@ -474,6 +510,7 @@ func siteDTO(row model.DistributionSite) SiteDTO {
|
||||
DisplayAccountEnabled: row.DisplayAccountEnabled,
|
||||
DefaultSupportGroupID: row.DefaultSupportGroupID,
|
||||
ListingQrcodeURL: row.ListingQrcodeURL,
|
||||
ReceiveRatioDelta: row.ReceiveRatioDelta,
|
||||
TaxEnabled: row.TaxEnabled,
|
||||
TaxRateBPS: row.TaxRateBPS,
|
||||
SettlementHoldDays: row.SettlementHoldDays,
|
||||
@@ -2097,6 +2134,7 @@ func (r *Repository) GetPublicSiteInfo(ctx context.Context, code, domain string)
|
||||
BannersJSON: site.BannersJSON,
|
||||
AnnouncementsJSON: site.AnnouncementsJSON,
|
||||
FooterInfoJSON: site.FooterInfoJSON,
|
||||
ReceiveRatioDelta: site.ReceiveRatioDelta,
|
||||
}
|
||||
if r.redis != nil {
|
||||
if bytes, err := json.Marshal(res); err == nil {
|
||||
@@ -2347,28 +2385,29 @@ func (r *Repository) ListReceivedListings(ctx context.Context, adminID, siteID u
|
||||
}
|
||||
|
||||
type receivedListingRow struct {
|
||||
ID uint64 `gorm:"column:id"`
|
||||
ListingNo string `gorm:"column:listing_no"`
|
||||
AccountID uint64 `gorm:"column:account_id"`
|
||||
OwnerID uint64 `gorm:"column:owner_id"`
|
||||
OwnerUsername string `gorm:"column:owner_username"`
|
||||
OwnerPhone string `gorm:"column:owner_phone"`
|
||||
GameName string `gorm:"column:game_name"`
|
||||
Title string `gorm:"column:title"`
|
||||
ServerRegion string `gorm:"column:server_region"`
|
||||
LoginPlatform string `gorm:"column:login_platform"`
|
||||
RankLevel string `gorm:"column:rank_level"`
|
||||
HafCoinAmount int64 `gorm:"column:haf_coin_amount"`
|
||||
PriceCent int64 `gorm:"column:price_cent"`
|
||||
DepositAmountCent int64 `gorm:"column:deposit_amount_cent"`
|
||||
Status string `gorm:"column:status"`
|
||||
ReviewStatus string `gorm:"column:review_status"`
|
||||
ReviewReason string `gorm:"column:review_reason"`
|
||||
InTransaction bool `gorm:"column:in_transaction"`
|
||||
DistributionSiteID uint64 `gorm:"column:distribution_site_id"`
|
||||
DisplayStatus string `gorm:"column:display_status"`
|
||||
CreatedAt time.Time `gorm:"column:created_at"`
|
||||
PublishedAt *time.Time `gorm:"column:published_at"`
|
||||
ID uint64 `gorm:"column:id"`
|
||||
ListingNo string `gorm:"column:listing_no"`
|
||||
AccountID uint64 `gorm:"column:account_id"`
|
||||
OwnerID uint64 `gorm:"column:owner_id"`
|
||||
OwnerUsername string `gorm:"column:owner_username"`
|
||||
OwnerPhone string `gorm:"column:owner_phone"`
|
||||
GameName string `gorm:"column:game_name"`
|
||||
Title string `gorm:"column:title"`
|
||||
ServerRegion string `gorm:"column:server_region"`
|
||||
LoginPlatform string `gorm:"column:login_platform"`
|
||||
RankLevel string `gorm:"column:rank_level"`
|
||||
HafCoinAmount int64 `gorm:"column:haf_coin_amount"`
|
||||
AssetSummary datatypes.JSON `gorm:"column:asset_summary"`
|
||||
PriceCent int64 `gorm:"column:price_cent"`
|
||||
DepositAmountCent int64 `gorm:"column:deposit_amount_cent"`
|
||||
Status string `gorm:"column:status"`
|
||||
ReviewStatus string `gorm:"column:review_status"`
|
||||
ReviewReason string `gorm:"column:review_reason"`
|
||||
InTransaction bool `gorm:"column:in_transaction"`
|
||||
DistributionSiteID uint64 `gorm:"column:distribution_site_id"`
|
||||
DisplayStatus string `gorm:"column:display_status"`
|
||||
CreatedAt time.Time `gorm:"column:created_at"`
|
||||
PublishedAt *time.Time `gorm:"column:published_at"`
|
||||
}
|
||||
|
||||
var rows []receivedListingRow
|
||||
@@ -2377,6 +2416,7 @@ func (r *Repository) ListReceivedListings(ctx context.Context, adminID, siteID u
|
||||
COALESCE(u.nickname, '') AS owner_username,
|
||||
COALESCE(u.phone, '') AS owner_phone,
|
||||
ga.game_name, ga.title, ga.server_region, ga.login_platform, ga.rank_level, ga.haf_coin_amount,
|
||||
ga.asset_summary,
|
||||
rl.price_cent, rl.deposit_amount_cent, rl.status, rl.review_status, rl.review_reason,
|
||||
rl.in_transaction, COALESCE(rl.distribution_site_id, 0) AS distribution_site_id,
|
||||
COALESCE(dsa.display_status, 'enabled') AS display_status,
|
||||
@@ -2396,27 +2436,31 @@ func (r *Repository) ListReceivedListings(ctx context.Context, adminID, siteID u
|
||||
if r.DisplayStatus == "disabled" {
|
||||
status = "offline"
|
||||
}
|
||||
pricing := listingpkg.ReceivePricingFromAssetSummary(r.AssetSummary)
|
||||
items = append(items, ReceivedListingDTO{
|
||||
ListingID: r.ID,
|
||||
ListingNo: r.ListingNo,
|
||||
SiteID: r.DistributionSiteID,
|
||||
AccountID: r.AccountID,
|
||||
OwnerID: r.OwnerID,
|
||||
OwnerPhone: maskedPhone,
|
||||
OwnerNickname: r.OwnerUsername,
|
||||
Title: r.Title,
|
||||
GameName: r.GameName,
|
||||
ServerRegion: r.ServerRegion,
|
||||
LoginPlatform: r.LoginPlatform,
|
||||
RankLevel: r.RankLevel,
|
||||
HafCoinAmount: r.HafCoinAmount,
|
||||
PriceCent: r.PriceCent,
|
||||
DepositAmountCent: r.DepositAmountCent,
|
||||
Status: status,
|
||||
ReviewStatus: r.ReviewStatus,
|
||||
ReviewReason: r.ReviewReason,
|
||||
PublishedAt: r.PublishedAt,
|
||||
CreatedAt: r.CreatedAt,
|
||||
ListingID: r.ID,
|
||||
ListingNo: r.ListingNo,
|
||||
SiteID: r.DistributionSiteID,
|
||||
AccountID: r.AccountID,
|
||||
OwnerID: r.OwnerID,
|
||||
OwnerPhone: maskedPhone,
|
||||
OwnerNickname: r.OwnerUsername,
|
||||
Title: r.Title,
|
||||
GameName: r.GameName,
|
||||
ServerRegion: r.ServerRegion,
|
||||
LoginPlatform: r.LoginPlatform,
|
||||
RankLevel: r.RankLevel,
|
||||
HafCoinAmount: r.HafCoinAmount,
|
||||
SellerRatio: pricing.SellerRatio,
|
||||
SellerTotalPriceCent: pricing.SellerTotalPriceCent,
|
||||
BuyerRatio: pricing.BuyerRatio,
|
||||
PriceCent: r.PriceCent,
|
||||
DepositAmountCent: r.DepositAmountCent,
|
||||
Status: status,
|
||||
ReviewStatus: r.ReviewStatus,
|
||||
ReviewReason: r.ReviewReason,
|
||||
PublishedAt: r.PublishedAt,
|
||||
CreatedAt: r.CreatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package distribution
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -8,6 +9,7 @@ import (
|
||||
"hfb_sys/backend/internal/database"
|
||||
"hfb_sys/backend/internal/model"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -666,7 +668,19 @@ func TestDistributionBrandingAndMarkup(t *testing.T) {
|
||||
t.Fatalf("cleared listing_qrcode_url = %q, want empty", qrCleared.ListingQrcodeURL)
|
||||
}
|
||||
|
||||
// Verify PublicSiteInfo contains branding
|
||||
delta := 3.5
|
||||
ratioUpdated, err := repo.UpdateSite(t.Context(), 0, site.ID, UpdateSiteRequest{ReceiveRatioDelta: &delta})
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateSite receive ratio failed: %v", err)
|
||||
}
|
||||
if ratioUpdated.ReceiveRatioDelta != 3.5 {
|
||||
t.Fatalf("receive_ratio_delta = %v, want 3.5", ratioUpdated.ReceiveRatioDelta)
|
||||
}
|
||||
negative := -1.0
|
||||
if _, err := repo.UpdateSite(t.Context(), 0, site.ID, UpdateSiteRequest{ReceiveRatioDelta: &negative}); !errors.Is(err, ErrInvalidAmount) {
|
||||
t.Fatalf("negative receive ratio err = %v, want ErrInvalidAmount", err)
|
||||
}
|
||||
|
||||
pubInfo, err := repo.GetPublicSiteInfo(t.Context(), "brand_site", "")
|
||||
if err != nil {
|
||||
t.Fatalf("GetPublicSiteInfo failed: %v", err)
|
||||
@@ -674,6 +688,9 @@ func TestDistributionBrandingAndMarkup(t *testing.T) {
|
||||
if pubInfo.LogoURL != "https://cdn.example.com/logo.png" {
|
||||
t.Fatalf("expected LogoURL, got: %+v", pubInfo)
|
||||
}
|
||||
if pubInfo.ReceiveRatioDelta != 3.5 {
|
||||
t.Fatalf("public receive_ratio_delta = %v, want 3.5", pubInfo.ReceiveRatioDelta)
|
||||
}
|
||||
|
||||
faviconOnly := "https://cdn.example.com/favicon2.ico"
|
||||
partial, err := repo.UpdateSiteBranding(t.Context(), 0, site.ID, UpdateSiteBrandingRequest{FaviconURL: &faviconOnly})
|
||||
@@ -746,12 +763,24 @@ func TestDistributionReceivedListingsAndWallet(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
summary, err := json.Marshal(map[string]any{
|
||||
"price_breakdown": map[string]any{
|
||||
"seller_ratio": 43.0,
|
||||
"seller_total_price": 232.6,
|
||||
"buyer_ratio": 38.0,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ga := model.GameAccount{
|
||||
OwnerID: user.ID,
|
||||
GameName: "delta_force",
|
||||
ServerRegion: "cn",
|
||||
LoginPlatform: "pc",
|
||||
Title: "满配三角洲账号",
|
||||
HafCoinAmount: 100_000_000,
|
||||
AssetSummary: datatypes.JSON(summary),
|
||||
}
|
||||
if err := db.Create(&ga).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -786,6 +815,9 @@ func TestDistributionReceivedListingsAndWallet(t *testing.T) {
|
||||
if item.ListingNo != "RL-99001" || item.GameName != "delta_force" || item.OwnerNickname != "seller01" {
|
||||
t.Fatalf("unexpected received listing: %+v", item)
|
||||
}
|
||||
if item.SellerRatio != 43 || item.SellerTotalPriceCent != 23260 || item.BuyerRatio != 38 {
|
||||
t.Fatalf("expected main-site receive pricing, got ratio=%v price=%d buyer=%v", item.SellerRatio, item.SellerTotalPriceCent, item.BuyerRatio)
|
||||
}
|
||||
|
||||
if err := repo.UpdateReceivedListingStatus(t.Context(), 0, listing.ID, "inactive"); !errors.Is(err, ErrInvalidListingStatus) {
|
||||
t.Fatalf("inactive status err = %v", err)
|
||||
|
||||
Reference in New Issue
Block a user