fix(distribution): 修正商品归属回填、禁止全站灌货并拒绝无效站点头
用货架写入时间与上传来源回滚误标产地,不再依赖绝对时间戳;同步仅收本站上传与显式勾选。
This commit is contained in:
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user