Files
junhong_cmp_fiber/internal/handler/app/client_recharge_order.go
huang b972a776d9
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m32s
重构充值订单模块:用 tb_recharge_order + tb_payment 替换 tb_asset_recharge_record
- 新增 RechargeOrder 和 Payment 模型及对应 Store
- 新增 ClientRechargeOrderHandler 提供充值订单列表/详情接口
- 修改 client_wallet.go 使用新表读写充值数据
- 修改 callback/payment.go 将 CRCH 订单路由到 rechargeOrderService
- 修改 client_order/service.go 的强充流程使用新表
- 修改 auto_purchase.go 从 tb_recharge_order 读取 linked_package_ids
- 修改 order/service.go 的 WalletPay 使用 tb_payment 记录
- 修改 wechat_config_store.go 从 tb_recharge_order 统计待支付充值数
- 移除 AssetRechargeStore 和 AssetRechargeRecord 的注册引用
- 修复文档生成器缺失 ClientRechargeOrder handler
- 状态枚举改为 0-based: Pending=0, Paid=1, Closed=2, Refunded=3
2026-04-15 11:00:32 +08:00

197 lines
5.4 KiB
Go

package app
import (
"context"
"strconv"
"strings"
"time"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
"github.com/break/junhong_cmp_fiber/internal/middleware"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/response"
)
type ClientRechargeOrderHandler struct {
rechargeOrderStore *postgres.RechargeOrderStore
paymentStore *postgres.PaymentStore
logger *zap.Logger
}
func NewClientRechargeOrderHandler(
rechargeOrderStore *postgres.RechargeOrderStore,
paymentStore *postgres.PaymentStore,
logger *zap.Logger,
) *ClientRechargeOrderHandler {
return &ClientRechargeOrderHandler{
rechargeOrderStore: rechargeOrderStore,
paymentStore: paymentStore,
logger: logger,
}
}
func (h *ClientRechargeOrderHandler) ListRechargeOrders(c *fiber.Ctx) error {
var req dto.ClientRechargeOrderListRequest
if err := c.QueryParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam)
}
if req.Page < 1 {
req.Page = 1
}
if req.PageSize < 1 {
req.PageSize = constants.DefaultPageSize
}
if req.PageSize > constants.MaxPageSize {
req.PageSize = constants.MaxPageSize
}
customerID, ok := middleware.GetCustomerID(c)
if !ok || customerID == 0 {
return errors.New(errors.CodeUnauthorized)
}
skipCtx := context.WithValue(c.UserContext(), constants.ContextKeySubordinateShopIDs, []uint{})
params := &postgres.ListRechargeOrderParams{
Page: req.Page,
PageSize: req.PageSize,
UserID: &customerID,
}
if req.Status > 0 {
params.Status = &req.Status
}
orders, total, err := h.rechargeOrderStore.List(skipCtx, params)
if err != nil {
return errors.Wrap(errors.CodeDatabaseError, err, "查询充值订单失败")
}
items := make([]dto.ClientRechargeOrderListItem, 0, len(orders))
for _, order := range orders {
if order == nil {
continue
}
items = append(items, dto.ClientRechargeOrderListItem{
RechargeOrderID: order.ID,
RechargeOrderNo: order.RechargeOrderNo,
Amount: order.Amount,
Status: order.Status,
StatusName: getRechargeOrderStatusName(order.Status),
AutoPurchaseStatus: order.AutoPurchaseStatus,
CreatedAt: order.CreatedAt.Format(time.RFC3339),
})
}
return response.SuccessWithPagination(c, items, total, req.Page, req.PageSize)
}
func (h *ClientRechargeOrderHandler) GetRechargeOrderDetail(c *fiber.Ctx) error {
idStr := c.Params("id")
if idStr == "" {
return errors.New(errors.CodeInvalidParam)
}
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam)
}
customerID, ok := middleware.GetCustomerID(c)
if !ok || customerID == 0 {
return errors.New(errors.CodeUnauthorized)
}
skipCtx := context.WithValue(c.UserContext(), constants.ContextKeySubordinateShopIDs, []uint{})
order, err := h.rechargeOrderStore.GetByID(skipCtx, uint(id))
if err != nil {
if strings.Contains(err.Error(), "record not found") {
return errors.New(errors.CodeNotFound, "充值订单不存在")
}
return errors.Wrap(errors.CodeDatabaseError, err, "查询充值订单失败")
}
if order.UserID != customerID {
return errors.New(errors.CodeForbidden, "无权访问该充值订单")
}
payments, _ := h.paymentStore.ListByOrderID(skipCtx, order.ID, model.PaymentOrderTypeRecharge)
var paymentDetails []dto.ClientRechargeOrderPaymentDetail
for _, p := range payments {
if p == nil {
continue
}
paymentDetails = append(paymentDetails, dto.ClientRechargeOrderPaymentDetail{
PaymentID: p.ID,
PaymentNo: p.PaymentNo,
PaymentMethod: p.PaymentMethod,
Amount: p.Amount,
Status: p.Status,
StatusName: getPaymentStatusName(p.Status),
ThirdPartyTradeNo: p.ThirdPartyTradeNo,
PaidAt: formatTimePtr(p.PaidAt),
CreatedAt: p.CreatedAt.Format(time.RFC3339),
})
}
resp := &dto.ClientRechargeOrderDetail{
RechargeOrderID: order.ID,
RechargeOrderNo: order.RechargeOrderNo,
Amount: order.Amount,
Status: order.Status,
StatusName: getRechargeOrderStatusName(order.Status),
AutoPurchaseStatus: order.AutoPurchaseStatus,
LinkedPackageIDs: order.LinkedPackageIDs,
CreatedAt: order.CreatedAt.Format(time.RFC3339),
PaidAt: formatTimePtr(order.PaidAt),
Payments: paymentDetails,
}
return response.Success(c, resp)
}
func getRechargeOrderStatusName(status int) string {
switch status {
case model.RechargeOrderStatusPending:
return "待支付"
case model.RechargeOrderStatusPaid:
return "已支付"
case model.RechargeOrderStatusClosed:
return "已关闭"
case model.RechargeOrderStatusRefunded:
return "已退款"
default:
return "未知"
}
}
func getPaymentStatusName(status int) string {
switch status {
case model.PaymentRecordStatusPending:
return "待支付"
case model.PaymentRecordStatusPaid:
return "已支付"
case model.PaymentRecordStatusFailed:
return "已失败"
case model.PaymentRecordStatusRefunded:
return "已退款"
default:
return "未知"
}
}
func formatTimePtr(t *time.Time) string {
if t == nil {
return ""
}
return t.Format(time.RFC3339)
}