fix(distribution): 修正商品归属回填、禁止全站灌货并拒绝无效站点头

用货架写入时间与上传来源回滚误标产地,不再依赖绝对时间戳;同步仅收本站上传与显式勾选。
This commit is contained in:
yml2213
2026-09-08 17:30:12 +08:00
parent 96bc6a4db6
commit 31bf6dd3b6
15 changed files with 287 additions and 84 deletions
@@ -41,8 +41,12 @@ var (
ErrDuplicateSiteCodeOrDomain = errors.New("distribution site code or domain already exists")
ErrDuplicateUsername = errors.New("username already exists")
ErrLiveMoneyMovementFrozen = errors.New("distribution settlement and withdrawal frozen until split rules are verified")
ErrTooManySyncListings = errors.New("too many listings to sync")
ErrSyncListingNotFound = errors.New("sync listing not found")
)
const maxSyncListingIDs = 200
func liveMoneyMovementEnabled() bool {
env := strings.ToLower(strings.TrimSpace(os.Getenv("APP_ENV")))
return env != "production" && env != "prod"
@@ -507,7 +511,26 @@ func (r *Repository) UpdateAccountDisplay(ctx context.Context, adminID, id uint6
return item, nil
}
func (r *Repository) SyncSiteAccounts(ctx context.Context, adminID, siteID uint64) (*SyncSiteAccountsResult, error) {
func uniquePositiveIDs(ids []uint64) []uint64 {
if len(ids) == 0 {
return nil
}
seen := make(map[uint64]struct{}, len(ids))
out := make([]uint64, 0, len(ids))
for _, id := range ids {
if id == 0 {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
out = append(out, id)
}
return out
}
func (r *Repository) SyncSiteAccounts(ctx context.Context, adminID, siteID uint64, listingIDs []uint64) (*SyncSiteAccountsResult, error) {
if r.db == nil {
return nil, ErrDependencyUnavailable
}
@@ -522,14 +545,40 @@ func (r *Repository) SyncSiteAccounts(ctx context.Context, adminID, siteID uint6
return nil, err
}
var activeListings []model.RentalListing
selectedIDs := uniquePositiveIDs(listingIDs)
if len(selectedIDs) > maxSyncListingIDs {
return nil, ErrTooManySyncListings
}
var candidates []model.RentalListing
if err := r.db.WithContext(ctx).
Where("status = ? AND review_status = ?", "published", "approved").
Where("distribution_site_id = ? AND status = ? AND review_status = ?", siteID, "published", "approved").
Order("id ASC").
Find(&activeListings).Error; err != nil {
Find(&candidates).Error; err != nil {
return nil, err
}
if len(selectedIDs) > 0 {
var selected []model.RentalListing
if err := r.db.WithContext(ctx).Where("id IN ?", selectedIDs).Find(&selected).Error; err != nil {
return nil, err
}
if len(selected) != len(selectedIDs) {
return nil, ErrSyncListingNotFound
}
seenListing := make(map[uint64]bool, len(candidates)+len(selected))
for _, l := range candidates {
seenListing[l.ID] = true
}
for _, l := range selected {
if seenListing[l.ID] {
continue
}
seenListing[l.ID] = true
candidates = append(candidates, l)
}
}
var existingAccounts []model.DistributionSiteAccount
if err := r.db.WithContext(ctx).
Where("site_id = ?", siteID).
@@ -546,7 +595,7 @@ func (r *Repository) SyncSiteAccounts(ctx context.Context, adminID, siteID uint6
seenAccount := make(map[uint64]bool)
var skippedCount int64
for _, l := range activeListings {
for _, l := range candidates {
if seenAccount[l.AccountID] {
continue
}
@@ -577,7 +626,7 @@ func (r *Repository) SyncSiteAccounts(ctx context.Context, adminID, siteID uint6
return &SyncSiteAccountsResult{
SyncedCount: int64(len(toInsert)),
SkippedCount: skippedCount,
TotalActive: int64(len(activeListings)),
TotalActive: int64(len(candidates)),
}, nil
}
@@ -1096,34 +1145,6 @@ func (r *Repository) OnboardSite(ctx context.Context, req OnboardSiteRequest) (*
return err
}
if displayEnabled {
var activeListings []model.RentalListing
if err := tx.Where("status = ? AND review_status = ?", "published", "approved").Order("id ASC").Find(&activeListings).Error; err != nil {
return err
}
if len(activeListings) > 0 {
siteAccounts := make([]model.DistributionSiteAccount, 0, len(activeListings))
seenAccount := make(map[uint64]bool)
for _, l := range activeListings {
if seenAccount[l.AccountID] {
continue
}
seenAccount[l.AccountID] = true
siteAccounts = append(siteAccounts, model.DistributionSiteAccount{
SiteID: site.ID,
AccountID: l.AccountID,
ListingID: l.ID,
DisplayStatus: "enabled",
})
}
if len(siteAccounts) > 0 {
if err := tx.Create(&siteAccounts).Error; err != nil {
return err
}
}
}
}
resp = OnboardSiteResponse{
Site: siteDTO(site),
Rule: ruleDTO(rule),