bindbox-game/internal/api/user/points_redeem_product_app.go
2025-12-26 12:22:32 +08:00

80 lines
2.9 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, PointsAmount: needPoints})
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)
}
}