feat(distribution): 支持分销上传来源追踪、主站审核展示与收售结算模式自动判定
This commit is contained in:
@@ -43,6 +43,8 @@ func MigrateListingLifecycleTestSchema(db *gorm.DB) error {
|
||||
&model.RentalListing{},
|
||||
&model.ListingUpload{},
|
||||
&model.ListingStatusEvent{},
|
||||
&model.DistributionSite{},
|
||||
&model.DistributionSiteAccount{},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,11 +40,12 @@ type RentalListing struct {
|
||||
ReviewStatus string `gorm:"size:32;not null;default:'none'" json:"review_status"`
|
||||
HandoffMode string `gorm:"size:16;not null;default:'owner';index" json:"handoff_mode"`
|
||||
SettlementMode string `gorm:"size:32;not null;default:'owner_wallet'" json:"settlement_mode"`
|
||||
ManagedAdminID *uint64 `gorm:"index" json:"managed_admin_id"`
|
||||
ReviewReason string `gorm:"size:255;not null;default:''" json:"review_reason"`
|
||||
PublishedAt *time.Time `json:"published_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
ManagedAdminID *uint64 `gorm:"index" json:"managed_admin_id"`
|
||||
DistributionSiteID *uint64 `gorm:"column:distribution_site_id;index" json:"distribution_site_id,omitempty"`
|
||||
ReviewReason string `gorm:"size:255;not null;default:''" json:"review_reason"`
|
||||
PublishedAt *time.Time `json:"published_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (RentalListing) TableName() string {
|
||||
|
||||
@@ -24,28 +24,66 @@ func distributionTablesPresent(tx *gorm.DB) bool {
|
||||
return distributionTablePresent
|
||||
}
|
||||
|
||||
// ResolveOrderSourceTx 校验站点、账号展示关系和生效规则,供正常订单创建事务写入快照引用。
|
||||
// 第一期仅启用 two_party_distributor_receive 模式,其他模式规则不会命中(见设计文档实施顺序)。
|
||||
// ResolveOrderSourceTx 校验收号方站点与售出方站点、账号展示关系和生效规则,供正常订单创建事务写入快照引用。
|
||||
func ResolveOrderSourceTx(tx *gorm.DB, siteCode string, listingID, accountID uint64, at time.Time) (*model.DistributionSite, *model.DistributionRuleVersion, error) {
|
||||
if siteCode == "" {
|
||||
var listing model.RentalListing
|
||||
var listingSiteID *uint64
|
||||
if listingID > 0 {
|
||||
if err := tx.Select("id, distribution_site_id").First(&listing, listingID).Error; err == nil {
|
||||
listingSiteID = listing.DistributionSiteID
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 两方均无分销站:纯主站交易
|
||||
if siteCode == "" && listingSiteID == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
var site model.DistributionSite
|
||||
if err := tx.Where("site_code = ? AND status = 'active' AND display_account_enabled = ?", siteCode, true).First(&site).Error; err != nil {
|
||||
|
||||
// 2. 模式一:分销网收号、主站卖出 (ModeTwoPartyDistributorReceive)
|
||||
if siteCode == "" && listingSiteID != nil {
|
||||
var site model.DistributionSite
|
||||
if err := tx.Where("id = ? AND status = 'active'", *listingSiteID).First(&site).Error; err != nil {
|
||||
return nil, nil, ErrSiteNotFound
|
||||
}
|
||||
var rule model.DistributionRuleVersion
|
||||
query := tx.Where("mode = ? AND status = 'active' AND effective_from <= ? AND (effective_to IS NULL OR effective_to > ?)", ModeTwoPartyDistributorReceive, at, at).
|
||||
Where("site_id = ? OR site_id IS NULL", site.ID).
|
||||
Order("CASE WHEN site_id IS NULL THEN 1 ELSE 0 END, effective_from DESC, id DESC")
|
||||
if err := query.First(&rule).Error; err != nil {
|
||||
return nil, nil, ErrRuleNotFound
|
||||
}
|
||||
return &site, &rule, nil
|
||||
}
|
||||
|
||||
// 3. 买家在分销站下单:校验售出站点状态与账号展示关系
|
||||
var sellSite model.DistributionSite
|
||||
if err := tx.Where("site_code = ? AND status = 'active' AND display_account_enabled = ?", siteCode, true).First(&sellSite).Error; err != nil {
|
||||
return nil, nil, ErrSiteNotFound
|
||||
}
|
||||
var relation model.DistributionSiteAccount
|
||||
if err := tx.Where("site_id = ? AND listing_id = ? AND account_id = ? AND display_status = 'enabled'", site.ID, listingID, accountID).First(&relation).Error; err != nil {
|
||||
if err := tx.Where("site_id = ? AND listing_id = ? AND account_id = ? AND display_status = 'enabled'", sellSite.ID, listingID, accountID).First(&relation).Error; err != nil {
|
||||
return nil, nil, ErrAccountDisplayNotFound
|
||||
}
|
||||
|
||||
// 4. 解析生效规则:优先匹配有效规则版本
|
||||
targetMode := ModeTwoPartyDistributorReceive
|
||||
if listingSiteID != nil && *listingSiteID != sellSite.ID {
|
||||
targetMode = ModeThreeParty
|
||||
}
|
||||
var rule model.DistributionRuleVersion
|
||||
query := tx.Where("mode = ? AND status = 'active' AND effective_from <= ? AND (effective_to IS NULL OR effective_to > ?)", ModeTwoPartyDistributorReceive, at, at).
|
||||
Where("site_id = ? OR site_id IS NULL", site.ID).
|
||||
Order("CASE WHEN site_id IS NULL THEN 1 ELSE 0 END, effective_from DESC, id DESC")
|
||||
query := tx.Where("status = 'active' AND effective_from <= ? AND (effective_to IS NULL OR effective_to > ?)", at, at).
|
||||
Where("site_id = ? OR site_id IS NULL", sellSite.ID)
|
||||
if targetMode == ModeThreeParty {
|
||||
query = query.Where("mode = ?", ModeThreeParty)
|
||||
} else {
|
||||
query = query.Where("mode IN (?, ?)", ModeTwoPartyDistributorReceive, ModeTwoPartyPlatformReceive).
|
||||
Order("CASE WHEN mode = '" + ModeTwoPartyDistributorReceive + "' THEN 0 ELSE 1 END")
|
||||
}
|
||||
query = query.Order("CASE WHEN site_id IS NULL THEN 1 ELSE 0 END, effective_from DESC, id DESC")
|
||||
if err := query.First(&rule).Error; err != nil {
|
||||
return nil, nil, ErrRuleNotFound
|
||||
}
|
||||
return &site, &rule, nil
|
||||
return &sellSite, &rule, nil
|
||||
}
|
||||
|
||||
// calculateForRule 按规则快照计算手续费、服务费和分成基数。
|
||||
@@ -99,6 +137,12 @@ func SnapshotPaidOrderTx(tx *gorm.DB, orderID uint64, grossPaidCent int64) error
|
||||
partyID := *order.DistributionSiteID
|
||||
if partyType == "platform" {
|
||||
partyID = 0
|
||||
} else if split.PartyRole == "distributor_a" {
|
||||
// 三方模式下 distributor_a 为商品收号站
|
||||
var listing model.RentalListing
|
||||
if err := tx.Select("distribution_site_id").First(&listing, order.ListingID).Error; err == nil && listing.DistributionSiteID != nil {
|
||||
partyID = *listing.DistributionSiteID
|
||||
}
|
||||
}
|
||||
parties = append(parties, model.DistributionOrderParty{OrderID: order.ID, SiteID: *order.DistributionSiteID, PartyRole: split.PartyRole, PartyType: partyType, PartyID: partyID, Ratio: split.Ratio, IncomeAmountCent: split.AmountCent, ProfitAmountCent: split.AmountCent})
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ type ListingDTO struct {
|
||||
ManagedAdminID *uint64 `json:"managed_admin_id,omitempty"`
|
||||
ReviewReason string `json:"review_reason"`
|
||||
PublishedAt *time.Time `json:"published_at"`
|
||||
DistributionSiteID *uint64 `json:"distribution_site_id,omitempty"`
|
||||
DistributionSiteCode string `json:"distribution_site_code,omitempty"`
|
||||
DistributionSiteName string `json:"distribution_site_name,omitempty"`
|
||||
ListingGroupConversationID uint64 `json:"listing_group_conversation_id,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
@@ -18,7 +18,8 @@ func (h *Handler) Create(c *gin.Context) {
|
||||
response.BadRequest(c, listingBindErrorMessage(err))
|
||||
return
|
||||
}
|
||||
item, err := h.service.Create(c.Request.Context(), ownerID, req)
|
||||
siteCode := strings.TrimSpace(c.GetHeader("X-Distribution-Site-Code"))
|
||||
item, err := h.service.Create(c.Request.Context(), ownerID, req, siteCode)
|
||||
if err != nil {
|
||||
writeListingError(c, err)
|
||||
return
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
func (r *Repository) Create(ctx context.Context, ownerID uint64, req CreateRequest, reviewRequired bool, publishCooldown time.Duration) (*ListingDTO, error) {
|
||||
func (r *Repository) Create(ctx context.Context, ownerID uint64, req CreateRequest, reviewRequired bool, publishCooldown time.Duration, siteCode ...string) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
now := time.Now()
|
||||
@@ -51,20 +51,44 @@ func (r *Repository) Create(ctx context.Context, ownerID uint64, req CreateReque
|
||||
if err := tx.Create(&account).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var site model.DistributionSite
|
||||
var siteID *uint64
|
||||
if len(siteCode) > 0 && strings.TrimSpace(siteCode[0]) != "" {
|
||||
trimmedSiteCode := strings.TrimSpace(siteCode[0])
|
||||
if err := tx.Where("site_code = ? AND status = 'active'", trimmedSiteCode).First(&site).Error; err == nil {
|
||||
siteID = &site.ID
|
||||
}
|
||||
}
|
||||
|
||||
priceCent := normalizedListingPriceCent(req)
|
||||
listing := model.RentalListing{
|
||||
ListingNo: listingNo,
|
||||
AccountID: account.ID,
|
||||
OwnerID: ownerID,
|
||||
PriceCent: priceCent,
|
||||
DepositAmountCent: req.DepositAmountCent,
|
||||
Status: listingStatus,
|
||||
ReviewStatus: reviewStatus,
|
||||
PublishedAt: publishedAt,
|
||||
ListingNo: listingNo,
|
||||
AccountID: account.ID,
|
||||
OwnerID: ownerID,
|
||||
PriceCent: priceCent,
|
||||
DepositAmountCent: req.DepositAmountCent,
|
||||
Status: listingStatus,
|
||||
ReviewStatus: reviewStatus,
|
||||
PublishedAt: publishedAt,
|
||||
DistributionSiteID: siteID,
|
||||
}
|
||||
if err := tx.Create(&listing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if siteID != nil {
|
||||
dsa := model.DistributionSiteAccount{
|
||||
SiteID: *siteID,
|
||||
AccountID: account.ID,
|
||||
ListingID: listing.ID,
|
||||
DisplayStatus: "enabled",
|
||||
}
|
||||
if err := tx.Create(&dsa).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := listingstatus.AppendTransition(tx, &listing, "", listingstatus.SourceSeller, listingstatus.ActorUser, ownerID, "发布上架"); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -80,6 +104,12 @@ func (r *Repository) Create(ctx context.Context, ownerID uint64, req CreateReque
|
||||
}
|
||||
|
||||
dto = toDTO(account, listing)
|
||||
if siteID != nil {
|
||||
dto.DistributionSiteID = siteID
|
||||
dto.DistributionSiteCode = site.SiteCode
|
||||
dto.DistributionSiteName = site.SiteName
|
||||
dto.SourceChannel = fmt.Sprintf("分销站 - %s (%s)", site.SiteName, site.SiteCode)
|
||||
}
|
||||
dto.ListingGroupConversationID = conversationID
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -18,8 +18,10 @@ type listingRow struct {
|
||||
Title string
|
||||
OwnerPhone string
|
||||
OwnerNickname string
|
||||
SourceChannel string `gorm:"column:source_channel"`
|
||||
IsExternalUpload bool `gorm:"column:is_external_upload"`
|
||||
SourceChannel string `gorm:"column:source_channel"`
|
||||
IsExternalUpload bool `gorm:"column:is_external_upload"`
|
||||
DistributionSiteCode string `gorm:"column:distribution_site_code"`
|
||||
DistributionSiteName string `gorm:"column:distribution_site_name"`
|
||||
Description string
|
||||
GameName string
|
||||
ServerRegion string
|
||||
@@ -189,11 +191,14 @@ func (row listingRow) toDTO() ListingDTO {
|
||||
ReviewStatus: reviewStatus,
|
||||
HandoffMode: row.HandoffMode,
|
||||
SettlementMode: row.SettlementMode,
|
||||
ManagedAdminID: row.ManagedAdminID,
|
||||
ReviewReason: reviewReason,
|
||||
PublishedAt: row.PublishedAt,
|
||||
CreatedAt: row.CreatedAt,
|
||||
UpdatedAt: row.UpdatedAt,
|
||||
ManagedAdminID: row.ManagedAdminID,
|
||||
DistributionSiteID: row.DistributionSiteID,
|
||||
DistributionSiteCode: row.DistributionSiteCode,
|
||||
DistributionSiteName: row.DistributionSiteName,
|
||||
ReviewReason: reviewReason,
|
||||
PublishedAt: row.PublishedAt,
|
||||
CreatedAt: row.CreatedAt,
|
||||
UpdatedAt: row.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,33 +207,34 @@ func toDTO(account model.GameAccount, listing model.RentalListing) *ListingDTO {
|
||||
screenshotURLS := cleanScreenshotURLs(decodeScreenshots(account.ScreenshotURLS))
|
||||
reviewStatus, reviewReason := normalizedReviewState(listing.Status, listing.ReviewStatus, listing.ReviewReason)
|
||||
return &ListingDTO{
|
||||
ID: listing.ID,
|
||||
ListingNo: listing.ListingNo,
|
||||
AccountID: account.ID,
|
||||
OwnerID: listing.OwnerID,
|
||||
Title: account.Title,
|
||||
Description: account.Description,
|
||||
GameName: account.GameName,
|
||||
ServerRegion: account.ServerRegion,
|
||||
LoginPlatform: account.LoginPlatform,
|
||||
RankLevel: account.RankLevel,
|
||||
HafCoinAmount: account.HafCoinAmount,
|
||||
AssetSummary: assetSummary,
|
||||
ScreenshotURLS: screenshotURLS,
|
||||
CoverURL: publicCoverURL(listing.ID, screenshotURLS, listing.Status, listing.ReviewStatus),
|
||||
PriceCent: listing.PriceCent,
|
||||
DepositAmountCent: listing.DepositAmountCent,
|
||||
IsAccelerated: isAcceleratedSale(assetSummary),
|
||||
InTransaction: listing.InTransaction,
|
||||
Status: listing.Status,
|
||||
ReviewStatus: reviewStatus,
|
||||
HandoffMode: listing.HandoffMode,
|
||||
SettlementMode: listing.SettlementMode,
|
||||
ManagedAdminID: listing.ManagedAdminID,
|
||||
ReviewReason: reviewReason,
|
||||
PublishedAt: listing.PublishedAt,
|
||||
CreatedAt: listing.CreatedAt,
|
||||
UpdatedAt: listing.UpdatedAt,
|
||||
ID: listing.ID,
|
||||
ListingNo: listing.ListingNo,
|
||||
AccountID: account.ID,
|
||||
OwnerID: listing.OwnerID,
|
||||
Title: account.Title,
|
||||
Description: account.Description,
|
||||
GameName: account.GameName,
|
||||
ServerRegion: account.ServerRegion,
|
||||
LoginPlatform: account.LoginPlatform,
|
||||
RankLevel: account.RankLevel,
|
||||
HafCoinAmount: account.HafCoinAmount,
|
||||
AssetSummary: assetSummary,
|
||||
ScreenshotURLS: screenshotURLS,
|
||||
CoverURL: publicCoverURL(listing.ID, screenshotURLS, listing.Status, listing.ReviewStatus),
|
||||
PriceCent: listing.PriceCent,
|
||||
DepositAmountCent: listing.DepositAmountCent,
|
||||
IsAccelerated: isAcceleratedSale(assetSummary),
|
||||
InTransaction: listing.InTransaction,
|
||||
Status: listing.Status,
|
||||
ReviewStatus: reviewStatus,
|
||||
HandoffMode: listing.HandoffMode,
|
||||
SettlementMode: listing.SettlementMode,
|
||||
ManagedAdminID: listing.ManagedAdminID,
|
||||
DistributionSiteID: listing.DistributionSiteID,
|
||||
ReviewReason: reviewReason,
|
||||
PublishedAt: listing.PublishedAt,
|
||||
CreatedAt: listing.CreatedAt,
|
||||
UpdatedAt: listing.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -220,13 +220,17 @@ func (r *Repository) baseQuery(ctx context.Context) *gorm.DB {
|
||||
Select(`l.*, a.title, a.description, a.game_name, a.server_region, a.login_platform, a.rank_level,
|
||||
a.haf_coin_amount, a.asset_summary, a.screenshot_urls, COALESCE(u.phone, '') AS owner_phone, COALESCE(u.nickname, '') AS owner_nickname,
|
||||
CASE WHEN lu.id IS NULL THEN 0 ELSE 1 END AS is_external_upload,
|
||||
COALESCE(src_site.site_code, '') AS distribution_site_code,
|
||||
COALESCE(src_site.site_name, '') AS distribution_site_name,
|
||||
CASE
|
||||
WHEN l.distribution_site_id IS NOT NULL AND src_site.id IS NOT NULL THEN CONCAT('分销站 - ', src_site.site_name, ' (', src_site.site_code, ')')
|
||||
WHEN lu.id IS NULL THEN ?
|
||||
WHEN COALESCE(lu.source_channel, '') = '' THEN ?
|
||||
ELSE lu.source_channel
|
||||
END AS source_channel`, sourceChannelWebsite, sourceChannelExternalUnknown).
|
||||
Joins("JOIN game_accounts AS a ON a.id = l.account_id").
|
||||
Joins("LEFT JOIN users AS u ON u.id = l.owner_id").
|
||||
Joins("LEFT JOIN distribution_sites AS src_site ON src_site.id = l.distribution_site_id").
|
||||
// 逐商品按 listing_id 索引定位最后一次导入,避免每次列表查询都对全量导入记录分组。
|
||||
Joins(`LEFT JOIN listing_uploads AS lu ON lu.id = (
|
||||
SELECT MAX(lu_latest.id) FROM listing_uploads AS lu_latest WHERE lu_latest.listing_id = l.id
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) Create(ctx context.Context, ownerID uint64, req CreateRequest) (*ListingDTO, error) {
|
||||
func (s *Service) Create(ctx context.Context, ownerID uint64, req CreateRequest, siteCode ...string) (*ListingDTO, error) {
|
||||
if s.repo == nil {
|
||||
return nil, ErrDependencyUnavailable
|
||||
}
|
||||
@@ -29,7 +29,11 @@ func (s *Service) Create(ctx context.Context, ownerID uint64, req CreateRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.repo.Create(ctx, ownerID, req, reviewRequired, cooldown)
|
||||
effectiveSiteCode := ""
|
||||
if len(siteCode) > 0 {
|
||||
effectiveSiteCode = siteCode[0]
|
||||
}
|
||||
return s.repo.Create(ctx, ownerID, req, reviewRequired, cooldown, effectiveSiteCode)
|
||||
}
|
||||
|
||||
func (s *Service) Update(ctx context.Context, ownerID uint64, id uint64, req UpdateRequest) (*ListingDTO, error) {
|
||||
|
||||
@@ -820,3 +820,71 @@ func TestUpdateScreenshots(t *testing.T) {
|
||||
t.Fatalf("unexpected coin screenshots: %#v", coinList)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateListingWithDistributionSiteCode(t *testing.T) {
|
||||
db := database.NewTestDB()
|
||||
if err := database.MigrateListingLifecycleTestSchema(db); err != nil {
|
||||
t.Fatalf("migrate err: %v", err)
|
||||
}
|
||||
repo := NewRepository(db, nil)
|
||||
|
||||
user := model.User{Phone: "18800000001", Nickname: "分销卖家", RealnameStatus: "verified", Status: "active"}
|
||||
db.Create(&user)
|
||||
|
||||
site := model.DistributionSite{
|
||||
SiteCode: "dist_test_1",
|
||||
SiteName: "测试分销商1",
|
||||
Domain: "d1.com",
|
||||
Status: "active",
|
||||
DisplayAccountEnabled: true,
|
||||
}
|
||||
db.Create(&site)
|
||||
|
||||
req := CreateRequest{
|
||||
Title: "分销上架商品",
|
||||
ServerRegion: "QQ",
|
||||
LoginPlatform: "PC",
|
||||
PriceCent: 8800,
|
||||
}
|
||||
|
||||
dto, err := repo.Create(context.Background(), user.ID, req, true, 0, "dist_test_1")
|
||||
if err != nil {
|
||||
t.Fatalf("repo.Create failed: %v", err)
|
||||
}
|
||||
|
||||
if dto.DistributionSiteID == nil || *dto.DistributionSiteID != site.ID {
|
||||
t.Fatalf("expected DistributionSiteID=%d, got %v", site.ID, dto.DistributionSiteID)
|
||||
}
|
||||
if dto.DistributionSiteCode != "dist_test_1" {
|
||||
t.Fatalf("expected dist_test_1, got %s", dto.DistributionSiteCode)
|
||||
}
|
||||
if dto.DistributionSiteName != "测试分销商1" {
|
||||
t.Fatalf("expected 测试分销商1, got %s", dto.DistributionSiteName)
|
||||
}
|
||||
expectedSource := "分销站 - 测试分销商1 (dist_test_1)"
|
||||
if dto.SourceChannel != expectedSource {
|
||||
t.Fatalf("expected %s, got %s", expectedSource, dto.SourceChannel)
|
||||
}
|
||||
|
||||
// 验证 distribution_site_accounts 自动创建并启用
|
||||
var dsa model.DistributionSiteAccount
|
||||
if err := db.Where("site_id = ? AND listing_id = ?", site.ID, dto.ID).First(&dsa).Error; err != nil {
|
||||
t.Fatalf("failed to find distribution_site_account: %v", err)
|
||||
}
|
||||
if dsa.DisplayStatus != "enabled" {
|
||||
t.Fatalf("expected enabled, got %s", dsa.DisplayStatus)
|
||||
}
|
||||
|
||||
// 验证审核工作台列表展示分销站来源
|
||||
pending, err := repo.ListPendingReview(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("ListPendingReview failed: %v", err)
|
||||
}
|
||||
if len(pending) != 1 {
|
||||
t.Fatalf("expected 1 pending item, got len=%d", len(pending))
|
||||
}
|
||||
if pending[0].SourceChannel != expectedSource {
|
||||
t.Fatalf("expected pending SourceChannel=%s, got %s", expectedSource, pending[0].SourceChannel)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package order
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"hfb_sys/backend/internal/model"
|
||||
@@ -146,13 +148,22 @@ func (r *Repository) Create(ctx context.Context, renterID uint64, req CreateRequ
|
||||
func orderAccountSourceSnapshot(tx *gorm.DB, listingID uint64) (string, string, error) {
|
||||
var upload model.ListingUpload
|
||||
err := tx.Where("listing_id = ?", listingID).Order("id DESC").First(&upload).Error
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return "internal", "", nil
|
||||
if err == nil {
|
||||
return "external", upload.SourceChannel, nil
|
||||
}
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return "", "", err
|
||||
}
|
||||
return "external", upload.SourceChannel, nil
|
||||
|
||||
var listing model.RentalListing
|
||||
if err := tx.Select("distribution_site_id").First(&listing, listingID).Error; err == nil && listing.DistributionSiteID != nil {
|
||||
var site model.DistributionSite
|
||||
if err := tx.Select("site_code, site_name").First(&site, *listing.DistributionSiteID).Error; err == nil {
|
||||
return "distribution", fmt.Sprintf("分销站 - %s (%s)", site.SiteName, site.SiteCode), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "internal", "", nil
|
||||
}
|
||||
|
||||
func listingHandoffMode(listing model.RentalListing) string {
|
||||
|
||||
Reference in New Issue
Block a user