修复线下提号后商品仍显示在「已上架」的问题

创建提号时将 listing/account 置为 rented 并记录状态事件,与正常订单锁定一致;完成提号对齐 completed/offline;取消提号恢复上架。补充 migration 修复历史数据。
This commit is contained in:
yml2213
2026-07-14 13:46:38 +08:00
parent 2ca6fd9306
commit 7b2d94e22d
2 changed files with 101 additions and 7 deletions
+55 -7
View File
@@ -33,7 +33,8 @@ func NewRepository(db *gorm.DB) *Repository {
}
// Create 创建提号订单(状态:提号中)。
// 锁定 listing.in_transaction,与正常订单互斥;不结算、不动钱包
// 与正常订单支付成功一致:listing 置 rented + in_transaction,从商品管理「已上架」中移出
// 不结算、不动钱包。
func (r *Repository) Create(ctx context.Context, req CreateRequest, adminID uint64, meta auditlog.Meta) (*PickupDTO, error) {
if r == nil || r.db == nil {
return nil, ErrDependencyUnavailable
@@ -63,7 +64,7 @@ func (r *Repository) Create(ctx context.Context, req CreateRequest, adminID uint
}
var account model.GameAccount
if err := tx.First(&account, listing.AccountID).Error; err != nil {
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&account, listing.AccountID).Error; err != nil {
return err
}
priceSnapshot := buildPickupPriceSnapshot(listing, account)
@@ -98,10 +99,28 @@ func (r *Repository) Create(ctx context.Context, req CreateRequest, adminID uint
}
createdID = pickup.ID
// 锁定商品:status=rented,从「已上架」列表移除,进入「已锁定」
fromStatus := listing.Status
listing.InTransaction = true
listing.Status = "rented"
account.Status = "rented"
if err := tx.Save(&listing).Error; err != nil {
return err
}
if err := tx.Save(&account).Error; err != nil {
return err
}
if err := listingstatus.AppendTransition(
tx,
&listing,
fromStatus,
listingstatus.SourcePickup,
listingstatus.ActorAdmin,
adminID,
"管理员线下提号锁定",
); err != nil {
return err
}
bid := pickup.ID
if err := notification.Append(tx, notification.Entry{
@@ -164,7 +183,9 @@ func (r *Repository) Complete(ctx context.Context, pickupID uint64, req Complete
return err
}
var account model.GameAccount
_ = tx.First(&account, pickup.AccountID).Error
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&account, pickup.AccountID).Error; err != nil {
return err
}
now := time.Now()
pickup.SettleAmountCent = req.SettleAmountCent
@@ -178,20 +199,25 @@ func (r *Repository) Complete(ctx context.Context, pickupID uint64, req Complete
return err
}
// listing 置 completedlistingLockedForOwnerMutation 已拦截此状态再上架
// listing 置 completed(售出终态,不可再上架),与正常订单 completeAssets 对齐
fromStatus := listing.Status
listing.InTransaction = true
listing.InTransaction = false
listing.Status = "completed"
listing.PublishedAt = nil
account.Status = "offline"
if err := tx.Save(&listing).Error; err != nil {
return err
}
if err := tx.Save(&account).Error; err != nil {
return err
}
if err := listingstatus.AppendTransition(
tx,
&listing,
fromStatus,
listingstatus.SourcePickup,
listingstatus.ActorAdmin,
0,
adminID,
"管理员提号完成",
); err != nil {
return err
@@ -244,7 +270,7 @@ func (r *Repository) Complete(ctx context.Context, pickupID uint64, req Complete
return r.FindByID(ctx, pickupID)
}
// Cancel 取消提号:解锁 listing.in_transaction,账号恢复可租。
// Cancel 取消提号:恢复 listing 为 published + 解锁 in_transaction,账号恢复可租。
func (r *Repository) Cancel(ctx context.Context, pickupID uint64, reason string, adminID uint64, meta auditlog.Meta) error {
if r == nil || r.db == nil {
return ErrDependencyUnavailable
@@ -264,16 +290,38 @@ func (r *Repository) Cancel(ctx context.Context, pickupID uint64, reason string,
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&listing, pickup.ListingID).Error; err != nil {
return err
}
var account model.GameAccount
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&account, pickup.AccountID).Error; err != nil {
return err
}
now := time.Now()
pickup.Status = StatusCancelled
pickup.CancelledAt = &now
if err := tx.Save(&pickup).Error; err != nil {
return err
}
// 取消提号:恢复上架,重新出现在商品管理「已上架」
fromStatus := listing.Status
listing.InTransaction = false
listing.Status = "published"
account.Status = "published"
if err := tx.Save(&listing).Error; err != nil {
return err
}
if err := tx.Save(&account).Error; err != nil {
return err
}
if err := listingstatus.AppendTransition(
tx,
&listing,
fromStatus,
listingstatus.SourcePickup,
listingstatus.ActorAdmin,
adminID,
"取消提号恢复上架",
); err != nil {
return err
}
bid := pickup.ID
_ = notification.Append(tx, notification.Entry{
UserID: pickup.OwnerID,