feat(shipping): 新增管理端撤销发货功能
- 新增 AdminCancelShipping handler,支持批量撤销待发货记录(status=1→5) - 事务内同步恢复 user_inventory.status=1 并清空 shipping_no - 在 remark 记录操作人 adminID,保证审计可追溯 - 注册路由 POST /api/admin/shipping/orders/cancel
This commit is contained in:
parent
b9a40df5c5
commit
0722e515c4
@ -1,6 +1,7 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@ -8,6 +9,7 @@ import (
|
||||
"bindbox-game/internal/code"
|
||||
"bindbox-game/internal/pkg/core"
|
||||
"bindbox-game/internal/pkg/validation"
|
||||
"bindbox-game/internal/repository/mysql/dao"
|
||||
"bindbox-game/internal/repository/mysql/model"
|
||||
)
|
||||
|
||||
@ -429,3 +431,91 @@ func (h *handler) GetShippingOrderDetail() core.HandlerFunc {
|
||||
ctx.Payload(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
type cancelShippingRequest struct {
|
||||
RecordIDs []int64 `json:"record_ids"`
|
||||
}
|
||||
|
||||
type cancelShippingResponse struct {
|
||||
CancelledCount int64 `json:"cancelled_count"`
|
||||
}
|
||||
|
||||
// AdminCancelShipping 管理端撤销发货申请
|
||||
// @Summary 管理端撤销发货申请
|
||||
// @Description 将待发货(status=1)的记录撤销为已取消(status=5),并恢复对应库存状态
|
||||
// @Tags 管理端.发货管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security LoginVerifyToken
|
||||
// @Param RequestBody body cancelShippingRequest true "请求参数"
|
||||
// @Success 200 {object} cancelShippingResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/shipping/orders/cancel [post]
|
||||
func (h *handler) AdminCancelShipping() core.HandlerFunc {
|
||||
return func(ctx core.Context) {
|
||||
req := new(cancelShippingRequest)
|
||||
if err := ctx.ShouldBindJSON(req); err != nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||||
return
|
||||
}
|
||||
if len(req.RecordIDs) == 0 {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "record_ids不能为空"))
|
||||
return
|
||||
}
|
||||
if len(req.RecordIDs) > 100 {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "单次最多处理100条记录"))
|
||||
return
|
||||
}
|
||||
|
||||
adminID := ctx.SessionUserInfo().Id
|
||||
var cancelledCount int64
|
||||
|
||||
err := h.writeDB.Transaction(func(tx *dao.Query) error {
|
||||
records, err := tx.ShippingRecords.WithContext(ctx.RequestContext()).
|
||||
Select(tx.ShippingRecords.ID, tx.ShippingRecords.InventoryID, tx.ShippingRecords.UserID).
|
||||
Where(tx.ShippingRecords.ID.In(req.RecordIDs...)).
|
||||
Where(tx.ShippingRecords.Status.Eq(1)).
|
||||
Find()
|
||||
if err != nil {
|
||||
return fmt.Errorf("query shipping records failed: %w", err)
|
||||
}
|
||||
if len(records) == 0 {
|
||||
return fmt.Errorf("没有找到待发货记录,可能已被处理")
|
||||
}
|
||||
|
||||
for _, rec := range records {
|
||||
res, err := tx.ShippingRecords.WithContext(ctx.RequestContext()).
|
||||
Where(tx.ShippingRecords.ID.Eq(rec.ID)).
|
||||
Where(tx.ShippingRecords.Status.Eq(1)).
|
||||
Update(tx.ShippingRecords.Status, 5)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update shipping record failed: %w", err)
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
remark := fmt.Sprintf("|shipping_cancelled_by_admin:%d", adminID)
|
||||
dbResult := tx.UserInventory.WithContext(ctx.RequestContext()).UnderlyingDB().Exec(
|
||||
"UPDATE user_inventory SET status=1, shipping_no='', remark=CONCAT(IFNULL(remark,''), ?) WHERE id=? AND user_id=?",
|
||||
remark, rec.InventoryID, rec.UserID,
|
||||
)
|
||||
if dbResult.Error != nil {
|
||||
return fmt.Errorf("restore inventory failed: %w", dbResult.Error)
|
||||
}
|
||||
if dbResult.RowsAffected == 0 {
|
||||
return fmt.Errorf("restore inventory failed: inventory id=%d not matched", rec.InventoryID)
|
||||
}
|
||||
cancelledCount++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Payload(&cancelShippingResponse{CancelledCount: cancelledCount})
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,6 +364,7 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo) (core.Mux, func(), er
|
||||
adminAuthApiRouter.GET("/shipping/orders", intc.RequireAdminAction("shipping:view"), adminHandler.ListShippingOrders())
|
||||
adminAuthApiRouter.GET("/shipping/orders/:id", intc.RequireAdminAction("shipping:view"), adminHandler.GetShippingOrderDetail())
|
||||
adminAuthApiRouter.PUT("/shipping/orders/batch", intc.RequireAdminAction("shipping:modify"), adminHandler.UpdateShippingBatch())
|
||||
adminAuthApiRouter.POST("/shipping/orders/cancel", intc.RequireAdminAction("shipping:modify"), adminHandler.AdminCancelShipping())
|
||||
|
||||
adminAuthApiRouter.POST("/pay/refunds", intc.RequireAdminAction("refund:create"), adminHandler.CreateRefund())
|
||||
adminAuthApiRouter.GET("/pay/refunds", intc.RequireAdminAction("refund:view"), adminHandler.ListRefunds())
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user