init: web_hgdjc_server

This commit is contained in:
2026-11-07 10:46:18 +08:00
commit b2ff6ac8ff
707 changed files with 147645 additions and 0 deletions
+140
View File
@@ -0,0 +1,140 @@
package web_recharge
import (
"context"
"errors"
"fmt"
"net/http"
"strconv"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/models/vipordermod"
"videoweb/pub/payCenter"
"videoweb/pub/pubdef"
srv_recharge "videoweb/web/service/srv_recharge"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"go.mongodb.org/mongo-driver/bson"
)
// newPayCenterCallbackDeps 将查单和入账边界集中,便于用内存替身验证回调不会错误入账。
type newPayCenterCallbackDeps struct {
findOrder func(context.Context, string) (*vipordermod.VipOrder, *srvdef.SrvErr)
queryOrder func(context.Context, string) (payCenter.QueryOrderInfo, error)
applyRecharge func(*gin.Context, *srv_recharge.BillCallbackParam) *srvdef.SrvErr
}
// NewPayCenterRchgCallBack 接收新支付中心签名充值通知。
// @Tags 支付回调
// @Summary 新支付中心充值回调
// @Description 校验商户号、MD5签名、金额及平台订单号,查单取得支付时间后按原流程入账;重复成功通知直接应答成功。
// @Accept json
// @Produce plain
// @Param request body payCenter.RechargeCallbackResp true "支付中心签名回调"
// @Success 200 {string} string "success"
// @Failure 400 {string} string "fail"
// @Router /api/web/third/newpaycenter/recharge/callback [POST]
func NewPayCenterRchgCallBack(ctx *gin.Context) {
deps := newPayCenterCallbackDeps{
findOrder: func(c context.Context, tradeNo string) (*vipordermod.VipOrder, *srvdef.SrvErr) {
return vipordermod.FindOneVipOrder(c, bson.M{vipordermod.FN.VipOrder.TradeNo: tradeNo})
},
queryOrder: func(c context.Context, tradeNo string) (payCenter.QueryOrderInfo, error) {
return (&payCenter.Recharge{Ctx: c, TradeNo: tradeNo}).QueryOrder(c)
},
applyRecharge: srv_recharge.OnPayCenterCallback,
}
handleNewPayCenterRchgCallBack(ctx, deps)
}
func handleNewPayCenterRchgCallBack(ctx *gin.Context, deps newPayCenterCallbackDeps) {
if err := processNewPayCenterRchgCallBack(ctx, deps); err != nil {
log.Error("【/api/web/third/newpaycenter/recharge/callback】充值回调处理失败", log.E(err))
ctx.String(http.StatusBadRequest, "fail")
return
}
ctx.String(http.StatusOK, "success")
}
func processNewPayCenterRchgCallBack(ctx *gin.Context, deps newPayCenterCallbackDeps) error {
var callback payCenter.RechargeCallbackResp
bindErr := ctx.ShouldBindBodyWith(&callback, binding.JSON)
bodyValue, _ := ctx.Get(gin.BodyBytesKey)
rawBody, _ := bodyValue.([]byte)
log.Info("【/api/web/third/newpaycenter/recharge/callback】收到充值回调",
log.Any("tradeNo", callback.TradeNo),
log.Any("requestBody", string(rawBody)),
log.Any("clientIP", ctx.ClientIP()),
)
if bindErr != nil {
return fmt.Errorf("回调参数解析失败: %w", bindErr)
}
request := &payCenter.Recharge{TradeNo: callback.TradeNo}
if request.GetMercID() == "" || request.GetAppSecret() == "" {
return errors.New("新支付中心回调配置缺少 mercID 或 mercSecret")
}
if callback.Code != http.StatusOK || callback.MercID != request.GetMercID() {
return fmt.Errorf("回调状态或商户不匹配,tradeNo=%s", callback.TradeNo)
}
signSource := strconv.Itoa(callback.Code) + callback.MercID + callback.OID + callback.PayMoney + callback.TradeNo + request.GetAppSecret()
if !payCenter.VerifySign(callback.Sign, signSource) {
return fmt.Errorf("回调验签失败,tradeNo=%s", callback.TradeNo)
}
amount, err := payCenter.ParseYuanToFen(callback.PayMoney)
if err != nil || amount <= 0 {
return fmt.Errorf("回调金额格式错误或非正数,tradeNo=%s", callback.TradeNo)
}
order, serr := deps.findOrder(ctx, callback.TradeNo)
if serr != nil {
return fmt.Errorf("查找本地充值订单失败,tradeNo=%s: %w", callback.TradeNo, serr)
}
if order == nil || order.TradeNo != callback.TradeNo {
return fmt.Errorf("本地充值订单不存在,tradeNo=%s", callback.TradeNo)
}
amountMismatch := amount != order.Amount
oidMismatch := order.Oid != "" && callback.OID != order.Oid
if amountMismatch || oidMismatch {
log.Error("【/api/web/third/newpaycenter/recharge/callback】回调金额或支付中心订单号不匹配",
log.Any("tradeNo", callback.TradeNo),
log.Any("userId", order.UserId),
log.Any("callbackPayMoneyYuan", callback.PayMoney),
log.Any("callbackAmountFen", amount),
log.Any("orderAmountFen", order.Amount),
log.Any("callbackOid", callback.OID),
log.Any("orderOid", order.Oid),
log.Any("orderStatus", order.Status),
log.Any("amountMismatch", amountMismatch),
log.Any("oidMismatch", oidMismatch),
)
return fmt.Errorf("回调金额或支付中心订单号不匹配,tradeNo=%s", callback.TradeNo)
}
if order.Status == pubdef.VipOrderSuccess {
log.Info("【/api/web/third/newpaycenter/recharge/callback】重复成功通知", log.Any("tradeNo", callback.TradeNo))
return nil
}
info, err := deps.queryOrder(ctx, callback.TradeNo)
if err != nil {
return fmt.Errorf("支付中心查单失败,tradeNo=%s: %w", callback.TradeNo, err)
}
if (info.MercID != "" && info.MercID != callback.MercID) || (info.TradeNo != "" && info.TradeNo != callback.TradeNo) {
return fmt.Errorf("支付中心查单返回了其他商户或订单,tradeNo=%s", callback.TradeNo)
}
paymentAt, err := time.ParseInLocation(time.RFC3339, info.PayTime, time.Local)
if err != nil {
return fmt.Errorf("支付中心支付时间无效,tradeNo=%s: %w", callback.TradeNo, err)
}
param := &srv_recharge.BillCallbackParam{
TradeNo: callback.TradeNo,
Oid: callback.OID,
RealAmount: amount,
PaymentAt: paymentAt,
}
if serr := deps.applyRecharge(ctx, param); serr != nil {
return fmt.Errorf("本地充值入账失败,tradeNo=%s: %w", callback.TradeNo, serr)
}
log.Info("【/api/web/third/newpaycenter/recharge/callback】充值入账成功", log.Any("tradeNo", callback.TradeNo), log.Any("userId", order.UserId), log.Any("amount", amount))
return nil
}
+34
View File
@@ -0,0 +1,34 @@
package web_recharge
import (
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"videoweb/web/service/srv_viporder"
"github.com/gin-gonic/gin"
)
// RechargeSummary 统计指定时间范围内的充值汇总
// @Tags wbapi统计
// @Summary 统计充值汇总
// @Description 按北京时间的开始/结束时间汇总支付成功订单金额与笔数
// @Accept json
// @Produce json
// @Param startTime query string true "开始时间,北京时间,支持 2006-01-02、2006-01-02 15:04:05、RFC3339"
// @Param endTime query string true "结束时间,北京时间,支持 2006-01-02、2006-01-02 15:04:05、RFC3339"
// @Success 200 {object} srv_viporder.RechargeSummaryResp "成功"
// @Failure 400 {string} string "失败"
// @Router /wbapi/jgdjweb/recharge/summary [GET]
func RechargeSummary(ctx *gin.Context) {
var req srv_viporder.RechargeSummaryReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
return
}
resp, serr := srv_viporder.GetRechargeSummary(ctx, &req)
if serr != nil {
common.ServerJSON(ctx, serr, nil)
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}