Files
yml2213andClaude Opus 4.8 be5d322c10 feat: 客服封存订单功能(号主失联场景)
新增客服「封存订单」动作,用于号主失联、无法联系的场景:单事务内
完成关闭订单、全量原路退款、永久封存关联商品、解散发布群、双方通知
与审计日志。

- 新增 listing 终态 sealed(封存),区别于可恢复的 offline
- listingLockedForOwnerMutation 锁定 sealed,号主无法再编辑/提审/上架
- 解散群聊按 listing_id 查发布群(listing_group)置 archived,
  阻断所有成员发言并留系统消息
- 新增 order.AdminSeal 及 /admin/orders/:id/seal 路由
- 前端:卖家页 PC/移动端 sealed 视为终态禁用操作,客服后台新增
  「封存订单」按钮与二次确认

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 22:52:20 +08:00

67 lines
1.9 KiB
Go

package order
import (
"context"
"gorm.io/gorm"
)
// RefundStarter 由支付模块适配实现,避免 order 直接依赖 payment。
type RefundStarter interface {
StartRefund(ctx context.Context, orderID uint64, refundAmountCent int64, bizType string, remark string) (status string, err error)
}
type RefundStarterFunc func(ctx context.Context, orderID uint64, refundAmountCent int64, bizType string, remark string) (status string, err error)
func (fn RefundStarterFunc) StartRefund(ctx context.Context, orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
return fn(ctx, orderID, refundAmountCent, bizType, remark)
}
type OrderChatNotifier interface {
NotifyNewConversation(conversationID uint64)
}
// OrderChatArchiver 由 chat 模块适配实现,在订单封存时于同一事务内解散关联群聊。
// 实际聊天群按 listing 关联(发布群 listing_group),故传 listingID。
type OrderChatArchiver interface {
ArchiveListingConversation(tx *gorm.DB, listingID uint64, reason string) error
}
type Dependencies struct {
ChatNotifier OrderChatNotifier
ChatArchiver OrderChatArchiver
RefundStarter RefundStarter
}
type refundAction struct {
OrderID uint64
RefundAmountCent int64
BizType string
Remark string
}
type Repository struct {
db *gorm.DB
chatNotifier OrderChatNotifier
chatArchiver OrderChatArchiver
refundStarter RefundStarter
}
const defaultPendingPaymentTimeoutMinutes = 15
func NewRepository(db *gorm.DB, deps ...Dependencies) *Repository {
repo := &Repository{db: db}
if len(deps) > 0 {
repo.chatNotifier = deps[0].ChatNotifier
repo.chatArchiver = deps[0].ChatArchiver
repo.refundStarter = deps[0].RefundStarter
}
return repo
}
func (r *Repository) NotifyNewConversation(conversationID uint64) {
if conversationID > 0 && r.chatNotifier != nil {
r.chatNotifier.NotifyNewConversation(conversationID)
}
}