bindbox-game/internal/api/admin/pay_orders_admin.go
邹方成 6ee627139c
Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 40s
feat: 新增支付测试小程序与微信支付集成
feat(pay): 添加支付API基础结构
feat(miniapp): 创建支付测试小程序页面与配置
feat(wechatpay): 配置微信支付参数与证书
fix(guild): 修复成员列表查询条件
docs: 更新代码规范文档与需求文档
style: 统一前后端枚举显示与注释格式
refactor(admin): 重构用户奖励发放接口参数处理
test(title): 添加称号效果参数验证测试
2025-11-17 00:42:08 +08:00

319 lines
14 KiB
Go

package admin
import (
"net/http"
"time"
"bindbox-game/internal/code"
"bindbox-game/internal/pkg/core"
"bindbox-game/internal/pkg/validation"
"bindbox-game/internal/repository/mysql/model"
)
type listPayOrdersRequest struct {
Page int `form:"page"`
PageSize int `form:"page_size"`
Status *int32 `form:"status"`
SourceType *int32 `form:"source_type"`
UserID *int64 `form:"user_id"`
OrderNo string `form:"order_no"`
IsConsumed *int32 `form:"is_consumed"`
StartDate string `form:"start_date"`
EndDate string `form:"end_date"`
PayStart string `form:"pay_start"`
PayEnd string `form:"pay_end"`
}
type listPayOrdersResponse struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int64 `json:"total"`
List []*model.Orders `json:"list"`
}
func (h *handler) ListPayOrders() core.HandlerFunc {
return func(ctx core.Context) {
req := new(listPayOrdersRequest)
rsp := new(listPayOrdersResponse)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 20
}
if req.PageSize > 100 {
req.PageSize = 100
}
q := h.readDB.Orders.WithContext(ctx.RequestContext()).ReadDB()
if req.Status != nil {
q = q.Where(h.readDB.Orders.Status.Eq(*req.Status))
}
if req.SourceType != nil {
q = q.Where(h.readDB.Orders.SourceType.Eq(*req.SourceType))
}
if req.UserID != nil {
q = q.Where(h.readDB.Orders.UserID.Eq(*req.UserID))
}
if req.OrderNo != "" {
q = q.Where(h.readDB.Orders.OrderNo.Eq(req.OrderNo))
}
if req.IsConsumed != nil {
q = q.Where(h.readDB.Orders.IsConsumed.Eq(*req.IsConsumed))
}
if req.StartDate != "" {
if t, err := time.Parse("2006-01-02", req.StartDate); err == nil {
q = q.Where(h.readDB.Orders.CreatedAt.Gte(t))
}
}
if req.EndDate != "" {
if t, err := time.Parse("2006-01-02", req.EndDate); err == nil {
t = t.Add(24 * time.Hour).Add(-time.Second)
q = q.Where(h.readDB.Orders.CreatedAt.Lte(t))
}
}
if req.PayStart != "" {
if t, err := time.Parse(time.RFC3339, req.PayStart); err == nil {
q = q.Where(h.readDB.Orders.PaidAt.Gte(t))
}
}
if req.PayEnd != "" {
if t, err := time.Parse(time.RFC3339, req.PayEnd); err == nil {
q = q.Where(h.readDB.Orders.PaidAt.Lte(t))
}
}
total, err := q.Count()
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21001, err.Error()))
return
}
rows, err := q.Order(h.readDB.Orders.ID.Desc()).Offset((req.Page-1)*req.PageSize).Limit(req.PageSize).Find()
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21002, err.Error()))
return
}
rsp.Page = req.Page
rsp.PageSize = req.PageSize
rsp.Total = total
rsp.List = rows
ctx.Payload(rsp)
}
}
type getPayOrderResponse struct {
Order *model.Orders `json:"order"`
Items []*model.OrderItems `json:"items"`
Shipments []*model.ShippingRecords `json:"shipments"`
Ledgers []*model.UserPointsLedger `json:"ledgers"`
User *model.Users `json:"user"`
Activity *struct{
ActivityID int64 `json:"activity_id"`
ActivityName string `json:"activity_name"`
IssueID int64 `json:"issue_id"`
IssueNumber string `json:"issue_number"`
IsWinner int32 `json:"is_winner"`
Level int32 `json:"level"`
RewardID int64 `json:"reward_id"`
RewardName string `json:"reward_name"`
ProductID int64 `json:"product_id"`
} `json:"activity"`
Payment *struct{
Status int32 `json:"status"`
ActualAmount int64 `json:"actual_amount"`
PaidAt string `json:"paid_at"`
PayPreorderID int64 `json:"pay_preorder_id"`
TransactionID string `json:"transaction_id"`
} `json:"payment"`
Refunds []*struct{
RefundNo string `json:"refund_no"`
Amount int64 `json:"amount"`
Status string `json:"status"`
Channel string `json:"channel"`
Reason string `json:"reason"`
CreatedAt string `json:"created_at"`
} `json:"refunds"`
RefundableAmount int64 `json:"refundable_amount"`
}
func (h *handler) GetPayOrderDetail() core.HandlerFunc {
return func(ctx core.Context) {
rsp := new(getPayOrderResponse)
orderNo := ctx.Param("order_no")
if orderNo == "" {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "缺少订单号"))
return
}
order, err := h.readDB.Orders.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Orders.OrderNo.Eq(orderNo)).First()
if err != nil || order == nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21003, "订单不存在"))
return
}
items, _ := h.readDB.OrderItems.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.OrderItems.OrderID.Eq(order.ID)).Find()
shipments, _ := h.readDB.ShippingRecords.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.ShippingRecords.OrderID.Eq(order.ID)).Find()
ledgers, _ := h.readDB.UserPointsLedger.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.UserPointsLedger.RefTable.Eq("orders"), h.readDB.UserPointsLedger.RefID.Eq(orderNo)).Find()
user, _ := h.readDB.Users.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Users.ID.Eq(order.UserID)).First()
var activityID int64
var activityName string
var issueID int64
var issueNumber string
var isWinner int32
var level int32
var rewardID int64
var rewardName string
var rewardProductID int64
if order.SourceType == 2 {
drawLog, _ := h.readDB.ActivityDrawLogs.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.ActivityDrawLogs.OrderID.Eq(order.ID)).First()
if drawLog != nil {
isWinner = drawLog.IsWinner
level = drawLog.Level
rewardID = drawLog.RewardID
issueID = drawLog.IssueID
issue, _ := h.readDB.ActivityIssues.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.ActivityIssues.ID.Eq(issueID)).First()
if issue != nil {
issueNumber = issue.IssueNumber
activityID = issue.ActivityID
activity, _ := h.readDB.Activities.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Activities.ID.Eq(activityID)).First()
if activity != nil {
activityName = activity.Name
}
}
if rewardID > 0 {
reward, _ := h.readDB.ActivityRewardSettings.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.ActivityRewardSettings.ID.Eq(rewardID)).First()
if reward != nil {
rewardName = reward.Name
rewardProductID = reward.ProductID
}
}
}
}
rsp.Activity = &struct{ActivityID int64 `json:"activity_id"`; ActivityName string `json:"activity_name"`; IssueID int64 `json:"issue_id"`; IssueNumber string `json:"issue_number"`; IsWinner int32 `json:"is_winner"`; Level int32 `json:"level"`; RewardID int64 `json:"reward_id"`; RewardName string `json:"reward_name"`; ProductID int64 `json:"product_id"`}{
ActivityID: activityID,
ActivityName: activityName,
IssueID: issueID,
IssueNumber: issueNumber,
IsWinner: isWinner,
Level: level,
RewardID: rewardID,
RewardName: rewardName,
ProductID: rewardProductID,
}
if user != nil { rsp.User = user }
rsp.Payment = &struct{Status int32 `json:"status"`; ActualAmount int64 `json:"actual_amount"`; PaidAt string `json:"paid_at"`; PayPreorderID int64 `json:"pay_preorder_id"`; TransactionID string `json:"transaction_id"`}{
Status: order.Status,
ActualAmount: order.ActualAmount,
PaidAt: order.PaidAt.Format("2006-01-02 15:04:05"),
PayPreorderID: order.PayPreorderID,
TransactionID: "",
}
tx, _ := h.readDB.PaymentTransactions.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.PaymentTransactions.OrderNo.Eq(order.OrderNo)).Order(h.readDB.PaymentTransactions.ID.Desc()).First()
if tx != nil {
rsp.Payment.PaidAt = tx.SuccessTime.Format("2006-01-02 15:04:05")
rsp.Payment.TransactionID = tx.TransactionID
}
var refundedSum int64
var refunds []*struct{ RefundNo string `json:"refund_no"`; Amount int64 `json:"amount"`; Status string `json:"status"`; Channel string `json:"channel"`; Reason string `json:"reason"`; CreatedAt string `json:"created_at"` }
prList, _ := h.readDB.PaymentRefunds.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.PaymentRefunds.OrderNo.Eq(order.OrderNo)).Order(h.readDB.PaymentRefunds.ID.Desc()).Find()
for _, r := range prList {
refundedSum += r.AmountRefund
refunds = append(refunds, &struct{ RefundNo string `json:"refund_no"`; Amount int64 `json:"amount"`; Status string `json:"status"`; Channel string `json:"channel"`; Reason string `json:"reason"`; CreatedAt string `json:"created_at"` }{ RefundNo: r.RefundNo, Amount: r.AmountRefund, Status: r.Status, Channel: r.Channel, Reason: r.Reason, CreatedAt: r.CreatedAt.Format("2006-01-02 15:04:05") })
}
var refundable int64 = order.ActualAmount - refundedSum
if refundable < 0 { refundable = 0 }
rsp.Refunds = refunds
rsp.RefundableAmount = refundable
rsp.Order = order
rsp.Items = items
rsp.Shipments = shipments
rsp.Ledgers = ledgers
ctx.Payload(rsp)
}
}
type updateOrderRemarkRequest struct {
Remark string `json:"remark"`
}
type simpleResponse struct {
Success bool `json:"success"`
}
func (h *handler) UpdateOrderRemark() core.HandlerFunc {
return func(ctx core.Context) {
req := new(updateOrderRemarkRequest)
rsp := new(simpleResponse)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
orderNo := ctx.Param("order_no")
if orderNo == "" {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "缺少订单号"))
return
}
order, err := h.readDB.Orders.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Orders.OrderNo.Eq(orderNo)).First()
if err != nil || order == nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21004, "订单不存在"))
return
}
_, err = h.writeDB.Orders.WithContext(ctx.RequestContext()).Where(h.readDB.Orders.ID.Eq(order.ID)).Updates(map[string]any{
h.writeDB.Orders.Remark.ColumnName().String(): req.Remark,
h.writeDB.Orders.UpdatedAt.ColumnName().String(): time.Now(),
})
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21005, err.Error()))
return
}
rsp.Success = true
ctx.Payload(rsp)
}
}
func (h *handler) CancelOrder() core.HandlerFunc {
return func(ctx core.Context) {
orderNo := ctx.Param("order_no")
if orderNo == "" {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "缺少订单号"))
return
}
order, err := h.readDB.Orders.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Orders.OrderNo.Eq(orderNo)).First()
if err != nil || order == nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21006, "订单不存在"))
return
}
_, err = h.writeDB.Orders.WithContext(ctx.RequestContext()).Where(h.readDB.Orders.ID.Eq(order.ID), h.readDB.Orders.Status.Eq(1)).Updates(map[string]any{
h.readDB.Orders.Status.ColumnName().String(): 3,
h.readDB.Orders.CancelledAt.ColumnName().String(): time.Now(),
})
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21007, err.Error()))
return
}
ctx.Payload(&simpleResponse{Success: true})
}
}
func (h *handler) ConsumeOrder() core.HandlerFunc {
return func(ctx core.Context) {
orderNo := ctx.Param("order_no")
if orderNo == "" {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "缺少订单号"))
return
}
order, err := h.readDB.Orders.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.Orders.OrderNo.Eq(orderNo)).First()
if err != nil || order == nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21008, "订单不存在"))
return
}
_, err = h.writeDB.Orders.WithContext(ctx.RequestContext()).Where(h.readDB.Orders.ID.Eq(order.ID), h.readDB.Orders.Status.Eq(2)).Updates(map[string]any{
h.readDB.Orders.IsConsumed.ColumnName().String(): 1,
})
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 21009, err.Error()))
return
}
ctx.Payload(&simpleResponse{Success: true})
}
}