bindbox-game/internal/api/user/points_redeem_product_app.go
邹方成 45815bfb7d chore: 清理无用文件与优化代码结构
refactor(utils): 修复密码哈希比较逻辑错误
feat(user): 新增按状态筛选优惠券接口
docs: 添加虚拟发货与任务中心相关文档
fix(wechat): 修正Code2Session上下文传递问题
test: 补充订单折扣与积分转换测试用例
build: 更新配置文件与构建脚本
style: 清理多余的空行与注释
2025-12-18 17:35:55 +08:00

80 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package app
import (
"bindbox-game/internal/code"
"bindbox-game/internal/pkg/core"
"bindbox-game/internal/pkg/validation"
usersvc "bindbox-game/internal/service/user"
"net/http"
"strconv"
)
type redeemProductRequest struct {
ProductID int64 `json:"product_id"`
Quantity int `json:"quantity"`
}
type redeemProductResponse struct {
Success bool `json:"success"`
LedgerID int64 `json:"ledger_id"`
OrderID int64 `json:"order_id"`
InventoryIDs []int64 `json:"inventory_ids"`
Message string `json:"message"`
}
// RedeemPointsToProduct 积分兑换商品
// @Summary 积分兑换商品
// @Description 使用积分按比率1元=100积分兑换商品生成系统发放订单与用户资产
// @Tags APP端.积分
// @Accept json
// @Produce json
// @Security LoginVerifyToken
// @Param RequestBody body redeemProductRequest true "请求参数"
// @Success 200 {object} redeemProductResponse
// @Failure 400 {object} code.Failure
// @Router /api/app/users/{user_id}/points/redeem-product [post]
// RedeemPointsToProduct 使用积分兑换商品处理器
// 功能:按商品价格扣减积分并生成系统发放订单与用户资产
// 参数:无(通过上下文获取 user_idbody 解析 product_id/quantity
// 返回core.HandlerFunc 处理 POST /api/app/users/{user_id}/points/redeem-product
func (h *handler) RedeemPointsToProduct() core.HandlerFunc {
return func(ctx core.Context) {
req := new(redeemProductRequest)
rsp := new(redeemProductResponse)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
if req.Quantity <= 0 {
req.Quantity = 1
}
userID := int64(ctx.SessionUserInfo().Id)
prod, err := h.readDB.Products.WithContext(ctx.RequestContext()).Where(h.readDB.Products.ID.Eq(req.ProductID)).First()
if err != nil || prod == nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 150101, "product not found"))
return
}
ptsPerUnit, _ := h.user.CentsToPoints(ctx.RequestContext(), prod.Price)
needPoints := ptsPerUnit * int64(req.Quantity)
if needPoints <= 0 {
needPoints = 1
}
ledgerID, err := h.user.ConsumePointsFor(ctx.RequestContext(), userID, needPoints, "products", strconv.FormatInt(req.ProductID, 10), "redeem product", "redeem_product")
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 150102, err.Error()))
return
}
resp, err := h.user.GrantReward(ctx.RequestContext(), userID, usersvc.GrantRewardRequest{ProductID: req.ProductID, Quantity: req.Quantity, Remark: prod.Name})
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 150103, err.Error()))
return
}
rsp.Success = true
rsp.LedgerID = ledgerID
rsp.OrderID = resp.OrderID
rsp.InventoryIDs = resp.InventoryIDs
rsp.Message = "ok"
ctx.Payload(rsp)
}
}