// 功能描述:本人充值结果查询、记录分页与请求冲突错误;版本:1.0.0。 package common import ( "strconv" "git.apinb.com/bsm-sdk/core/errcode" "git.apinb.com/bsm-sdk/core/infra" "git.apinb.com/heqiapp/platforms/backend/api/internal/impl" "git.apinb.com/heqiapp/platforms/backend/api/internal/models" "github.com/gin-gonic/gin" "gorm.io/gorm" ) var ErrRechargeRequestConflict = errcode.NewError(2411, "充值请求已存在,请保持原金额和支付方式") // rechargePublic 只投影本人查看所需字段,不暴露钱包主键、渠道密钥和原始支付参数。 func rechargePublic(order models.WalletRechargeOrder) gin.H { return gin.H{"identity": order.Identity, "recharge_no": order.RechargeNo, "recharge_status": order.RechargeStatus, "amount": order.Amount, "channel": order.Channel, "created_at": order.CreatedAt, "completed_at": order.CompletedAt} } // GetRecharge 以本地已验签回调的入账事实确认结果;支付渠道已付与钱包已入账分别返回。 func GetRecharge(client string) gin.HandlerFunc { return func(ctx *gin.Context) { owner, ok := currentOwner(ctx, client) if !ok { return } var order models.WalletRechargeOrder query := impl.DBService.Where("owner_type = ? AND owner_identity = ?", owner.Type, owner.Identity) if request := ctx.Param("request"); request != "" { query = query.Where("request_no = ?", request) } else { query = query.Where("identity = ?", ctx.Param("identity")) } if err := query.First(&order).Error; err != nil { if err == gorm.ErrRecordNotFound { ctx.Status(404) infra.Response.Error(ctx, errcode.ErrRecordNotFound) } else { infra.Response.Error(ctx, err) } return } response := rechargePublic(order) var paymentOrder models.PaymentOrder err := impl.DBService.Where("business_type = ? AND business_identity = ? AND user_identity = ?", "recharge", order.Identity, owner.Identity). Order("id desc").First(&paymentOrder).Error if err != nil && err != gorm.ErrRecordNotFound { infra.Response.Error(ctx, err) return } // 缺少支付单不推断为支付成功或失败,前端应保留待确认状态。 if err == nil { response["payment_status"] = paymentOrder.PaymentStatus response["expires_at"] = paymentOrder.ExpiresAt } infra.Response.Success(ctx, response) } } // ListRecharges 每次至多50条;主体类型和标识双重过滤,游标只影响本人范围。 func ListRecharges(client string) gin.HandlerFunc { return func(ctx *gin.Context) { var before uint64 if raw := ctx.Query("cursor"); raw != "" { var err error before, err = strconv.ParseUint(raw, 10, 64) if err != nil || before == 0 { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } } owner, ok := currentOwner(ctx, client) if !ok { return } query := impl.DBService.Where("owner_type = ? AND owner_identity = ?", owner.Type, owner.Identity) if before != 0 { query = query.Where("id < ?", before) } var orders []models.WalletRechargeOrder if err := query.Order("id desc").Limit(51).Find(&orders).Error; err != nil { infra.Response.Error(ctx, err) return } next := "" if len(orders) > 50 { orders = orders[:50] next = strconv.FormatUint(orders[49].ID, 10) } items := make([]gin.H, 0, len(orders)) for _, order := range orders { items = append(items, rechargePublic(order)) } infra.Response.Success(ctx, gin.H{"items": items, "next_cursor": next}) } }