feat: 完善 Rock 发货异常闭环与绑定判定
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"affiliate_dash/internal/middleware"
|
||||
"affiliate_dash/internal/model"
|
||||
"affiliate_dash/internal/pkg/response"
|
||||
"affiliate_dash/internal/service"
|
||||
|
||||
@@ -15,11 +16,12 @@ import (
|
||||
)
|
||||
|
||||
type RockHandler struct {
|
||||
rockSvc *service.RockService
|
||||
rockSvc *service.RockService
|
||||
deliverySvc *service.DeliveryService
|
||||
}
|
||||
|
||||
func NewRockHandler(rockSvc *service.RockService) *RockHandler {
|
||||
return &RockHandler{rockSvc: rockSvc}
|
||||
func NewRockHandler(rockSvc *service.RockService, deliverySvc *service.DeliveryService) *RockHandler {
|
||||
return &RockHandler{rockSvc: rockSvc, deliverySvc: deliverySvc}
|
||||
}
|
||||
|
||||
// actorPtr 把 0 值用户 ID 转成 nil,便于审计字段留空。
|
||||
@@ -493,6 +495,123 @@ func (h *RockHandler) ListDeliveryLogs(c *gin.Context) {
|
||||
response.OK(c, gin.H{"list": logs})
|
||||
}
|
||||
|
||||
func (h *RockHandler) ListTokenIncidents(c *gin.Context) {
|
||||
idUint, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的 Token ID")
|
||||
return
|
||||
}
|
||||
list, err := h.rockSvc.ListRockTokenIncidents(c.Request.Context(), uint(idUint))
|
||||
if err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"list": list})
|
||||
}
|
||||
|
||||
func (h *RockHandler) ListIncidents(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
result, err := h.rockSvc.ListRockDeliveryIncidents(
|
||||
c.Request.Context(),
|
||||
strings.TrimSpace(c.Query("status")),
|
||||
strings.TrimSpace(c.Query("category")),
|
||||
page,
|
||||
pageSize,
|
||||
)
|
||||
if err != nil {
|
||||
response.ServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{
|
||||
"list": result.List,
|
||||
"total": result.Total,
|
||||
"page": page,
|
||||
"page_size": pageSize,
|
||||
})
|
||||
}
|
||||
|
||||
type resolveIncidentReq struct {
|
||||
Note string `json:"note"`
|
||||
}
|
||||
|
||||
func (h *RockHandler) ResolveIncident(c *gin.Context) {
|
||||
idUint, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil || idUint == 0 {
|
||||
response.BadRequest(c, "无效的异常记录 ID")
|
||||
return
|
||||
}
|
||||
var req resolveIncidentReq
|
||||
_ = c.ShouldBindJSON(&req)
|
||||
if err := h.rockSvc.ResolveRockDeliveryIncident(
|
||||
c.Request.Context(),
|
||||
uint(idUint),
|
||||
req.Note,
|
||||
actorPtr(middleware.GetUserID(c)),
|
||||
); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"message": "异常记录已标记处理"})
|
||||
}
|
||||
|
||||
type retryIncidentReq struct {
|
||||
Note string `json:"note"`
|
||||
}
|
||||
|
||||
func (h *RockHandler) RetryIncident(c *gin.Context) {
|
||||
idUint, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil || idUint == 0 {
|
||||
response.BadRequest(c, "无效的异常记录 ID")
|
||||
return
|
||||
}
|
||||
if h.deliverySvc == nil {
|
||||
response.ServerError(c, "发货服务未初始化")
|
||||
return
|
||||
}
|
||||
var req retryIncidentReq
|
||||
_ = c.ShouldBindJSON(&req)
|
||||
actor := actorPtr(middleware.GetUserID(c))
|
||||
plan, err := h.rockSvc.ApproveRockIncidentRetry(c.Request.Context(), uint(idUint), req.Note, actor)
|
||||
if err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
result, retryErr := h.deliverySvc.SubmitForMerchant(
|
||||
plan.Order.MerchantID,
|
||||
0,
|
||||
plan.Order.OrderNo,
|
||||
plan.Token.ExpectedUID,
|
||||
strconv.FormatUint(uint64(plan.Token.ID), 10),
|
||||
)
|
||||
if retryErr != nil {
|
||||
if blocking, findErr := h.rockSvc.HasBlockingRockIncident(c.Request.Context(), plan.Order.OrderNo); findErr == nil && blocking == nil {
|
||||
_, _ = h.rockSvc.RecordRockIncident(
|
||||
c.Request.Context(),
|
||||
&plan.Token,
|
||||
plan.Order.OrderNo,
|
||||
model.RockIncidentCategoryOther,
|
||||
"人工重试失败: "+retryErr.Error(),
|
||||
0,
|
||||
"",
|
||||
)
|
||||
}
|
||||
response.BadRequest(c, "人工重试失败: "+retryErr.Error())
|
||||
return
|
||||
}
|
||||
if err := h.rockSvc.CompleteRockIncidentRetry(
|
||||
c.Request.Context(),
|
||||
plan.Token.ID,
|
||||
plan.Order.OrderNo,
|
||||
req.Note,
|
||||
actor,
|
||||
); err != nil {
|
||||
response.ServerError(c, "发货已提交,但关闭异常记录失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
response.OK(c, result)
|
||||
}
|
||||
|
||||
// ReleaseToken 把使用中的提货链接释放回可用库存;上游异常时需人工强制确认。
|
||||
func (h *RockHandler) ReleaseToken(c *gin.Context) {
|
||||
idUint, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
@@ -522,7 +641,7 @@ func (h *RockHandler) ReleaseToken(c *gin.Context) {
|
||||
response.OK(c, gin.H{"message": message})
|
||||
}
|
||||
|
||||
// RefreshStaleTokens 一键刷新异常 Token(绑定错误 + 使用超时 + 绑定超时,同步执行,单次最多 20 条)。
|
||||
// RefreshStaleTokens 一键刷新异常 Token(绑定错误 + 待绑定超时 + 绑定后未发货,同步执行,单次最多 20 条)。
|
||||
func (h *RockHandler) RefreshStaleTokens(c *gin.Context) {
|
||||
result, err := h.rockSvc.RefreshAllStaleTokens(c.Request.Context())
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user