更新工具版本和优化订单控制器逻辑

- 将 golang 版本从 1.24.3 更新至 1.24.4。
- 在 OrderController 中优化了订单查询、调度和更新的逻辑,增强了错误处理和状态检查,确保在处理订单时能够更准确地反馈状态信息。
- 增强了 MerchantQuery 方法的参数验证,确保在获取商户信息时能够正确处理错误情况。
This commit is contained in:
danial
2025-06-08 23:02:20 +08:00
parent b724ac2937
commit 13ec550f77
8 changed files with 1764 additions and 1756 deletions

View File

@@ -1 +1 @@
golang 1.24.3
golang 1.24.4

View File

@@ -1,222 +1,222 @@
package controllers
import (
"context"
"fmt"
"gateway/internal/config"
"gateway/internal/models/merchant"
"gateway/internal/models/order"
"gateway/internal/models/response"
"gateway/internal/models/road"
"gateway/internal/otelTrace"
"gateway/internal/schema/query"
"gateway/internal/service"
"gateway/internal/service/supplier/third_party"
"gateway/internal/utils"
"slices"
"strconv"
"strings"
"time"
"go.uber.org/zap"
"github.com/beego/beego/v2/server/web"
"github.com/bytedance/sonic"
)
type OrderController struct {
web.Controller
}
func (c *OrderController) OrderQuery() {
ctx := context.Background()
bankOrderId := c.GetString("bankOrderId")
otelTrace.Logger.WithContext(ctx).Info(fmt.Sprintf("获取订单信息:%s", bankOrderId), zap.String("bankOrderId", bankOrderId))
qy := query.SupplierOrderQueryResult(ctx, bankOrderId)
c.Ctx.WriteString(qy)
return
}
func (c *OrderController) OrderSchedule() {
ctx := c.Ctx.Request.Context()
bankOrderId := strings.TrimSpace(c.GetString("bankOrderId"))
orderInfo := order.GetOrderByBankOrderId(ctx, bankOrderId)
if orderInfo.Status == "success" {
c.Ctx.WriteString("成功状态订单不可重新调度")
return
}
if orderInfo.Status == "wait" && orderInfo.CreateTime.Add(time.Minute).After(time.Now()) {
c.Ctx.WriteString("处于等待订单状态需要在订单创建3分钟后才可以重新调度")
return
}
roadInfo := road.GetRoadInfoByRoadUid(ctx, orderInfo.RoadUid)
if !slices.Contains( third_party.GetThirdSupplierKeys(), roadInfo.ProductUid) {
c.Ctx.WriteString("当前通道不允许重新调度")
return
}
supplierByCode := third_party.GetPaySupplierByCode(roadInfo.ProductUid)
if supplierByCode == nil {
c.Ctx.WriteString("当前订单通道不存在")
return
}
merchantInfo := merchant.GetMerchantByUid(ctx, orderInfo.MerchantUid)
//修改订单状态
err := order.UpdateOrderStatus(ctx, orderInfo.BankOrderId, "wait", "重新调度成功")
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("修改订单状态失败", zap.Error(err))
c.Ctx.WriteString("修改订单状态失败")
return
}
scanData := supplierByCode.Scan(ctx, orderInfo, roadInfo, merchantInfo)
order.InsertCardReturnDataByBankId(ctx, orderInfo.BankOrderId, scanData.ReturnData)
if scanData.Status == "01" {
service.SolvePaySuccess(ctx, orderInfo.BankOrderId, orderInfo.OrderAmount, "", scanData.ReturnData)
c.Ctx.WriteString("调度成功并回调成功")
return
}
if scanData.Status == "00" {
c.Ctx.WriteString("success")
return
}
// 插入处理失败的动账通知
service.SolvePayFail(ctx, orderInfo.BankOrderId, orderInfo.BankTransId, scanData.ReturnData)
c.Ctx.WriteString("三方订单提交失败")
}
func (c *OrderController) OrderUpdate() {
ctx := context.Background()
bankOrderId := c.GetString("bankOrderId")
solveType := c.GetString("solveType")
orderInfo := order.GetOrderByBankOrderId(ctx, bankOrderId)
orderInfo.Operator = c.GetString("operator")
flag := false
if orderInfo.BankOrderId == "" {
otelTrace.Logger.WithContext(ctx).Error(fmt.Sprintf("该订单不存在, bankOrderId = %s", bankOrderId), zap.String("bankOrderId", bankOrderId))
} else {
switch solveType {
case config.SUCCESS:
flag = service.SolvePaySuccess(ctx, bankOrderId, orderInfo.FactAmount, orderInfo.BankTransId, "手动修正至成功")
case config.FAIL:
flag = service.SolvePayFail(ctx, bankOrderId, orderInfo.BankTransId, "手动修正至失败")
case config.FREEZE_AMOUNT:
// 将这笔订单进行冻结
flag = service.SolveOrderFreeze(ctx, bankOrderId)
case config.UNFREEZE_AMOUNT:
// 将这笔订单金额解冻
flag = service.SolveOrderUnfreeze(ctx, bankOrderId)
case config.REFUND:
if orderInfo.Status == config.SUCCESS {
flag = service.SolveRefund(ctx, bankOrderId)
}
case config.ORDERROLL:
if orderInfo.Status == config.SUCCESS {
flag = service.SolveOrderRoll(ctx, bankOrderId)
}
default:
otelTrace.Logger.WithContext(ctx).Error("不存在这样的处理类型")
}
if flag {
c.Ctx.WriteString(config.SUCCESS)
} else {
c.Ctx.WriteString(config.FAIL)
}
}
c.StopRun()
}
func (c *OrderController) MerchantQuery() {
ctx := c.Ctx.Request.Context()
appKey := strings.TrimSpace(c.GetString("appKey"))
orderNo := strings.TrimSpace(c.GetString("orderNo"))
timestamp := strings.TrimSpace(c.GetString("timestamp"))
sign := strings.TrimSpace(c.GetString("sign"))
if appKey == "" || orderNo == "" || timestamp == "" || sign == "" {
resp := response.Resp{
Code: -1,
Msg: "参数错误",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
merchantInfo := merchant.GetMerchantByPasskey(ctx, appKey)
if merchantInfo.Id == 0 {
resp := response.Resp{
Code: -1,
Msg: "key错误",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
tmpSign := utils.GetMD5SignMF(map[string]any{
"appKey": appKey,
"orderNo": orderNo,
"timestamp": timestamp,
}, merchantInfo.MerchantSecret)
tmpSign2 := utils.GetMD5Sign(ctx, map[string]any{
"appKey": appKey,
"orderNo": orderNo,
"timestamp": timestamp,
}, []string{"appKey", "orderNo", "timestamp"}, merchantInfo.MerchantSecret)
if tmpSign != sign && tmpSign2 != sign {
resp := response.Resp{
Code: -1,
Msg: "签名错误",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
orderInfo := order.GetOrderByMerchantOrderId(ctx, orderNo)
if orderInfo.Id == 0 {
resp := response.Resp{
Code: -1,
Msg: "订单不存在",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
exValue, err := sonic.GetFromString(orderInfo.ExValue)
if err != nil {
resp := response.Resp{
Code: -1,
Msg: "内部错误",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
cardNo, _ := exValue.Get("cardNo").String()
cardPwd, _ := exValue.Get("data").String()
_ = c.JSONResp(response.Resp{
Code: 0,
Msg: "订单获取成功",
Data: response.OrderQueryResp{
OrderNo: orderInfo.BankOrderId,
CardNo: cardNo,
CardPwd: cardPwd,
Status: orderInfo.Status,
FaceVal: orderInfo.FactAmount,
CardReturnData: orderInfo.CardReturnData,
Amount: strconv.FormatFloat(orderInfo.ShowAmount, 'f', -1, 64),
},
})
_ = c.ServeJSON()
}
package controllers
import (
"context"
"fmt"
"gateway/internal/config"
"gateway/internal/models/merchant"
"gateway/internal/models/order"
"gateway/internal/models/response"
"gateway/internal/models/road"
"gateway/internal/otelTrace"
"gateway/internal/schema/query"
"gateway/internal/service"
"gateway/internal/service/supplier/third_party"
"gateway/internal/utils"
"slices"
"strconv"
"strings"
"time"
"go.uber.org/zap"
"github.com/beego/beego/v2/server/web"
"github.com/bytedance/sonic"
)
type OrderController struct {
web.Controller
}
func (c *OrderController) OrderQuery() {
ctx := context.Background()
bankOrderId := c.GetString("bankOrderId")
otelTrace.Logger.WithContext(ctx).Info(fmt.Sprintf("获取订单信息:%s", bankOrderId), zap.String("bankOrderId", bankOrderId))
qy := query.SupplierOrderQueryResult(ctx, bankOrderId)
c.Ctx.WriteString(qy)
return
}
func (c *OrderController) OrderSchedule() {
ctx := c.Ctx.Request.Context()
bankOrderId := strings.TrimSpace(c.GetString("bankOrderId"))
orderInfo := order.GetOrderByBankOrderId(ctx, bankOrderId)
if orderInfo.Status == "success" {
c.Ctx.WriteString("成功状态订单不可重新调度")
return
}
if orderInfo.Status == "wait" && orderInfo.CreateTime.Add(time.Minute).After(time.Now()) {
c.Ctx.WriteString("处于等待订单状态需要在订单创建3分钟后才可以重新调度")
return
}
roadInfo := road.GetRoadInfoByRoadUid(ctx, orderInfo.RoadUid)
if !slices.Contains(third_party.GetThirdSupplierKeys(), roadInfo.ProductUid) {
c.Ctx.WriteString("当前通道不允许重新调度")
return
}
supplierByCode := third_party.GetPaySupplierByCode(roadInfo.ProductUid)
if supplierByCode == nil {
c.Ctx.WriteString("当前订单通道不存在")
return
}
merchantInfo := merchant.GetMerchantByUid(ctx, orderInfo.MerchantUid)
//修改订单状态
err := order.UpdateOrderStatus(ctx, orderInfo.BankOrderId, "wait", "重新调度成功")
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("修改订单状态失败", zap.Error(err))
c.Ctx.WriteString("修改订单状态失败")
return
}
scanData := supplierByCode.Scan(ctx, orderInfo, roadInfo, merchantInfo)
order.InsertCardReturnDataByBankId(ctx, orderInfo.BankOrderId, scanData.ReturnData)
if scanData.Status == "01" {
service.SolvePaySuccess(ctx, orderInfo.BankOrderId, orderInfo.OrderAmount, "", scanData.ReturnData)
c.Ctx.WriteString("调度成功并回调成功")
return
}
if scanData.Status == "00" {
c.Ctx.WriteString("success")
return
}
// 插入处理失败的动账通知
service.SolvePayFail(ctx, orderInfo.BankOrderId, orderInfo.BankTransId, scanData.ReturnData)
c.Ctx.WriteString("三方订单提交失败")
}
func (c *OrderController) OrderUpdate() {
ctx := context.Background()
bankOrderId := c.GetString("bankOrderId")
solveType := c.GetString("solveType")
orderInfo := order.GetOrderByBankOrderId(ctx, bankOrderId)
orderInfo.Operator = c.GetString("operator")
flag := false
if orderInfo.BankOrderId == "" {
otelTrace.Logger.WithContext(ctx).Error(fmt.Sprintf("该订单不存在, bankOrderId = %s", bankOrderId), zap.String("bankOrderId", bankOrderId))
} else {
switch solveType {
case config.SUCCESS:
flag = service.SolvePaySuccess(ctx, bankOrderId, orderInfo.FactAmount, orderInfo.BankTransId, "手动修正至成功")
case config.FAIL:
flag = service.SolvePayFail(ctx, bankOrderId, orderInfo.BankTransId, "手动修正至失败")
case config.FREEZE_AMOUNT:
// 将这笔订单进行冻结
flag = service.SolveOrderFreeze(ctx, bankOrderId)
case config.UNFREEZE_AMOUNT:
// 将这笔订单金额解冻
flag = service.SolveOrderUnfreeze(ctx, bankOrderId)
case config.REFUND:
if orderInfo.Status == config.SUCCESS {
flag = service.SolveRefund(ctx, bankOrderId)
}
case config.ORDERROLL:
if orderInfo.Status == config.SUCCESS {
flag = service.SolveOrderRoll(ctx, bankOrderId)
}
default:
otelTrace.Logger.WithContext(ctx).Error("不存在这样的处理类型")
}
if flag {
c.Ctx.WriteString(config.SUCCESS)
} else {
c.Ctx.WriteString(config.FAIL)
}
}
c.StopRun()
}
func (c *OrderController) MerchantQuery() {
ctx := c.Ctx.Request.Context()
appKey := strings.TrimSpace(c.GetString("appKey"))
orderNo := strings.TrimSpace(c.GetString("orderNo"))
timestamp := strings.TrimSpace(c.GetString("timestamp"))
sign := strings.TrimSpace(c.GetString("sign"))
if appKey == "" || orderNo == "" || timestamp == "" || sign == "" {
resp := response.Resp{
Code: -1,
Msg: "参数错误",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
merchantInfo := merchant.GetMerchantByPasskey(ctx, appKey)
if merchantInfo.Id == 0 {
resp := response.Resp{
Code: -1,
Msg: "key错误",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
tmpSign := utils.GetMD5SignMF(map[string]any{
"appKey": appKey,
"orderNo": orderNo,
"timestamp": timestamp,
}, merchantInfo.MerchantSecret)
tmpSign2 := utils.GetMD5Sign(ctx, map[string]any{
"appKey": appKey,
"orderNo": orderNo,
"timestamp": timestamp,
}, []string{"appKey", "orderNo", "timestamp"}, merchantInfo.MerchantSecret)
if tmpSign != sign && tmpSign2 != sign {
resp := response.Resp{
Code: -1,
Msg: "签名错误",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
orderInfo := order.GetOrderByMerchantOrderId(ctx, orderNo)
if orderInfo.Id == 0 {
resp := response.Resp{
Code: -1,
Msg: "订单不存在",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
exValue, err := sonic.GetFromString(orderInfo.ExValue)
if err != nil {
resp := response.Resp{
Code: -1,
Msg: "内部错误",
}
_ = c.JSONResp(resp)
_ = c.ServeJSON()
return
}
cardNo, _ := exValue.Get("cardNo").String()
cardPwd, _ := exValue.Get("data").String()
_ = c.JSONResp(response.Resp{
Code: 0,
Msg: "订单获取成功",
Data: response.OrderQueryResp{
OrderNo: orderInfo.BankOrderId,
CardNo: cardNo,
CardPwd: cardPwd,
Status: orderInfo.Status,
FaceVal: orderInfo.FactAmount,
CardReturnData: orderInfo.CardReturnData,
Amount: strconv.FormatFloat(orderInfo.ShowAmount, 'f', -1, 64),
},
})
_ = c.ServeJSON()
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,114 +1,114 @@
package accounts
import (
"context"
"gateway/internal/otelTrace"
"time"
"github.com/beego/beego/v2/client/orm"
"go.uber.org/zap"
)
type AccountInfo struct {
Id int
Status string
AccountUid string
AccountName string
Balance float64 // 账户总余额
SettleAmount float64 // 已经结算的金额
LoanAmount float64 // 账户押款金额
FreezeAmount float64 // 账户冻结金额
WaitAmount float64 // 待结算资金
PayforAmount float64 // 代付在途金额
// AbleBalance float64 //账户可用金额
CreateTime time.Time
UpdateTime time.Time
}
const ACCOUNT_INFO = "account_info"
func InsetAcount(ctx context.Context, account AccountInfo) bool {
o := orm.NewOrm()
_, err := o.Insert(&account)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("insert account fail: ", zap.Error(err))
return false
}
return true
}
func GetAccountByUid(ctx context.Context, accountUid string) AccountInfo {
o := orm.NewOrm()
var account AccountInfo
_, err := o.QueryTable(ACCOUNT_INFO).Filter("account_uid", accountUid).Limit(1).All(&account)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("get account by uid fail: ", zap.Error(err))
}
return account
}
func GetAccountLenByMap(ctx context.Context, params map[string]string) int {
o := orm.NewOrm()
qs := o.QueryTable(ACCOUNT_INFO)
for k, v := range params {
if len(v) > 0 {
qs = qs.Filter(k, v)
}
}
cnt, err := qs.Limit(-1).OrderBy("-update_time").Count()
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("get account len by map fail: ", zap.Error(err))
}
return int(cnt)
}
func GetAccountByMap(ctx context.Context, params map[string]string, displayCount, offset int) []AccountInfo {
o := orm.NewOrm()
var accountList []AccountInfo
qs := o.QueryTable(ACCOUNT_INFO)
for k, v := range params {
if len(v) > 0 {
qs = qs.Filter(k, v)
}
}
_, err := qs.Limit(displayCount, offset).OrderBy("-update_time").All(&accountList)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("get account by map fail: ", zap.Error(err))
}
return accountList
}
func GetAllAccount(ctx context.Context) []AccountInfo {
o := orm.NewOrm()
var accountList []AccountInfo
_, err := o.QueryTable(ACCOUNT_INFO).Limit(-1).All(&accountList)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("get all account fail: ", zap.Error(err))
}
return accountList
}
func UpdateAccount(ctx context.Context, account AccountInfo) bool {
o := orm.NewOrm()
_, err := o.Update(&account)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("update account fail: ", zap.Error(err))
return false
}
return true
}
func DeleteAccountByUid(ctx context.Context, accountUid string) bool {
o := orm.NewOrm()
_, err := o.QueryTable(ACCOUNT_INFO).Filter("account_uid", accountUid).Delete()
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("delete account fail: ", zap.Error(err))
return false
}
return true
}
package accounts
import (
"context"
"gateway/internal/otelTrace"
"time"
"github.com/beego/beego/v2/client/orm"
"go.uber.org/zap"
)
type AccountInfo struct {
Id int
Status string
AccountUid string
AccountName string
Balance float64 // 账户总余额
SettleAmount float64 // 已经结算的金额
LoanAmount float64 // 账户押款金额
FreezeAmount float64 // 账户冻结金额
WaitAmount float64 // 待结算资金
PayforAmount float64 // 代付在途金额
// AbleBalance float64 //账户可用金额
CreateTime time.Time
UpdateTime time.Time
}
const ACCOUNT_INFO = "account_info"
func InsetAcount(ctx context.Context, account AccountInfo) bool {
o := orm.NewOrm()
_, err := o.Insert(&account)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("insert account fail: ", zap.Error(err))
return false
}
return true
}
func GetAccountByUid(ctx context.Context, accountUid string) AccountInfo {
o := orm.NewOrm()
var account AccountInfo
_, err := o.QueryTable(ACCOUNT_INFO).Filter("account_uid", accountUid).Limit(1).All(&account)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("get account by uid fail: ", zap.Error(err))
}
return account
}
func GetAccountLenByMap(ctx context.Context, params map[string]string) int {
o := orm.NewOrm()
qs := o.QueryTable(ACCOUNT_INFO)
for k, v := range params {
if len(v) > 0 {
qs = qs.Filter(k, v)
}
}
cnt, err := qs.Limit(-1).OrderBy("-update_time").Count()
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("get account len by map fail: ", zap.Error(err))
}
return int(cnt)
}
func GetAccountByMap(ctx context.Context, params map[string]string, displayCount, offset int) []AccountInfo {
o := orm.NewOrm()
var accountList []AccountInfo
qs := o.QueryTable(ACCOUNT_INFO)
for k, v := range params {
if len(v) > 0 {
qs = qs.Filter(k, v)
}
}
_, err := qs.Limit(displayCount, offset).OrderBy("-update_time").All(&accountList)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("get account by map fail: ", zap.Error(err))
}
return accountList
}
func GetAllAccount(ctx context.Context) []AccountInfo {
o := orm.NewOrm()
var accountList []AccountInfo
_, err := o.QueryTable(ACCOUNT_INFO).Limit(-1).All(&accountList)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("get all account fail: ", zap.Error(err))
}
return accountList
}
func UpdateAccount(ctx context.Context, account AccountInfo) bool {
o := orm.NewOrm()
_, err := o.Update(&account)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("update account fail: ", zap.Error(err))
return false
}
return true
}
func DeleteAccountByUid(ctx context.Context, accountUid string) bool {
o := orm.NewOrm()
_, err := o.QueryTable(ACCOUNT_INFO).Filter("account_uid", accountUid).Delete()
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("delete account fail: ", zap.Error(err))
return false
}
return true
}

View File

@@ -1,170 +1,169 @@
package service
import (
"context"
"encoding/json"
"errors"
"gateway/internal/config"
"gateway/internal/otelTrace"
"gateway/internal/service/supplier"
"gateway/internal/models/merchant"
"gateway/internal/schema/response"
"strconv"
"github.com/duke-git/lancet/v2/convertor"
"go.uber.org/zap"
)
// GetMerchantInfoByPayKey 通过payKey获取商户信息
func GetMerchantInfoByPayKey(ctx context.Context, payKey string) (merchantInfo merchant.MerchantInfo, err error) {
merchantInfo = merchant.GetMerchantByPasskey(ctx, payKey)
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
err = errors.New("商户不存在,请联系商户")
return
} else if merchantInfo.Status != config.ACTIVE {
err = errors.New("商户状态已经被冻结或者被删除,请联系商户!")
return
}
return
}
// GetMerchantInfo 获取商户信息
func GetMerchantInfo(ctx context.Context, params map[string]any) *response.PayBaseResp {
c := new(response.PayBaseResp)
c.Params = params
merchantInfo := merchant.GetMerchantByPasskey(ctx, convertor.ToString(params["payKey"]))
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
c.Code = -1
c.Msg = "商户不存在或者paykey有误请联系管理员"
} else if merchantInfo.Status != config.ACTIVE {
c.Code = -1
c.Msg = "商户状态已经被冻结或者被删除,请联系管理员!"
} else {
c.MerchantInfo = merchantInfo
}
return c
}
func JudgeParams(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
c = OrderIsValid(ctx, c)
c = NotifyUrlIsValid(ctx, c)
c = OrderPeriodIsValid(ctx, c)
c = OrderPriceIsValid(ctx, c)
c = ExValueIsValid(ctx, c)
return c
}
func ExValueIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["exValue"] == "" || len(convertor.ToString(c.Params["exValue"])) == 0 {
c.Code = -1
c.Msg = "扩展参数不能为空"
}
isRedeemValid := true
exRedeemValue := supplier.RedeemCardInfo{}
if err := json.Unmarshal([]byte(convertor.ToString(c.Params["exValue"])), &exRedeemValue); err != nil {
otelTrace.Logger.WithContext(ctx).Error("提交卡密格式错误,请检查", zap.Any("exValue", c.Params["exValue"]), zap.Error(err))
isRedeemValid = false
}
if exRedeemValue.Data == "" || len(exRedeemValue.Data) == 0 {
isRedeemValid = false
}
if !isRedeemValid {
c.Code = -1
c.Msg = "提交卡密格式错误,请检查"
}
return c
}
func CompleteRedeemExValue(exValueStr string, faceValue string) (string, error) {
exValue := supplier.RedeemCardInfo{}
if err := json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
return "", err
}
exValue.FaceType = faceValue
res, err := json.Marshal(&exValue)
return string(res), err
}
func GetCompleteRedeemExValue(exValueStr string, faceValue string) (exValue supplier.RedeemCardInfo, err error) {
exValue = supplier.RedeemCardInfo{}
if err = json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
return exValue, err
}
exValue.FaceType = faceValue
return
}
func CompleteRechargeExValue(exValueStr string, faceValue string) (string, error) {
exValue := supplier.RechargeCardInfo{}
if err := json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
return "", err
}
exValue.FaceType = faceValue
res, err := json.Marshal(&exValue)
return string(res), err
}
// NotifyUrlIsValid 判断回调地址是否符合规则
func NotifyUrlIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["notifyUrl"] == "" || len(convertor.ToString(c.Params["notifyUrl"])) == 0 {
c.Code = -1
c.Msg = "订单回调不能为空"
}
return c
}
// OsTypeIsValid 判断设备类型是否符合规则
func OsTypeIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["osType"] == "" || len(convertor.ToString(c.Params["osType"])) == 0 {
c.Code = -1
c.Msg = "支付设备系统类型不能为空,默认填写\"1\"即可"
}
return c
}
func OrderPeriodIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderPeriod"] == "" || len(convertor.ToString(c.Params["orderPeriod"])) == 0 {
c.Code = -1
c.Msg = "订单过期时间不能为空,默认填写\"1\"即可"
}
return c
}
// OrderPriceIsValid 判断订单金额
func OrderPriceIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderPrice"] == "" || len(convertor.ToString(c.Params["orderPrice"])) == 0 {
c.Code = -1
c.Msg = "订单金额不能为空"
return c
}
a, err := strconv.ParseFloat(convertor.ToString(c.Params["orderPrice"]), 64)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("order price is invalid ", zap.Any("orderPrice", c.Params["orderPrice"]), zap.Error(err))
c.Code = -1
c.Msg = "订单金额非法"
}
c.OrderAmount = a
return c
}
// OrderIsValid 判断金额订单号是否为空或者有重复
func OrderIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderNo"] == "" || len(convertor.ToString(c.Params["orderNo"])) == 0 {
c.Code = -1
c.Msg = "商户订单号不能为空"
return c
}
return c
}
// IpIsWhite 判断ip是否在白名单中
func IpIsWhite() bool {
// TODO
return true
}
package service
import (
"context"
"encoding/json"
"errors"
"gateway/internal/config"
"gateway/internal/otelTrace"
"gateway/internal/service/supplier"
"gateway/internal/models/merchant"
"gateway/internal/schema/response"
"strconv"
"github.com/duke-git/lancet/v2/convertor"
"go.uber.org/zap"
)
// GetMerchantInfoByPayKey 通过payKey获取商户信息
func GetMerchantInfoByPayKey(ctx context.Context, payKey string) (merchantInfo merchant.MerchantInfo, err error) {
merchantInfo = merchant.GetMerchantByPasskey(ctx, payKey)
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
err = errors.New("商户不存在,请联系商户")
return
} else if merchantInfo.Status != config.ACTIVE {
err = errors.New("商户状态已经被冻结或者被删除,请联系商户!")
return
}
return
}
// GetMerchantInfo 获取商户信息
func GetMerchantInfo(ctx context.Context, params map[string]any) *response.PayBaseResp {
c := new(response.PayBaseResp)
c.Params = params
merchantInfo := merchant.GetMerchantByPasskey(ctx, convertor.ToString(params["payKey"]))
if merchantInfo.MerchantUid == "" || len(merchantInfo.MerchantUid) == 0 {
c.Code = -1
c.Msg = "商户不存在或者paykey有误请联系管理员"
} else if merchantInfo.Status != config.ACTIVE {
c.Code = -1
c.Msg = "商户状态已经被冻结或者被删除,请联系管理员!"
} else {
c.MerchantInfo = merchantInfo
}
return c
}
func JudgeParams(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
c = OrderIsValid(ctx, c)
c = NotifyUrlIsValid(ctx, c)
c = OrderPeriodIsValid(ctx, c)
c = OrderPriceIsValid(ctx, c)
c = ExValueIsValid(ctx, c)
return c
}
func ExValueIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["exValue"] == "" || len(convertor.ToString(c.Params["exValue"])) == 0 {
c.Code = -1
c.Msg = "扩展参数不能为空"
}
isRedeemValid := true
exRedeemValue := supplier.RedeemCardInfo{}
if err := json.Unmarshal([]byte(convertor.ToString(c.Params["exValue"])), &exRedeemValue); err != nil {
otelTrace.Logger.WithContext(ctx).Error("提交卡密格式错误,请检查", zap.Any("exValue", c.Params["exValue"]), zap.Error(err))
isRedeemValid = false
}
if exRedeemValue.Data == "" || len(exRedeemValue.Data) == 0 {
isRedeemValid = false
}
if !isRedeemValid {
c.Code = -1
c.Msg = "提交卡密格式错误,请检查"
}
return c
}
func CompleteRedeemExValue(exValueStr string, faceValue string) (string, error) {
exValue := supplier.RedeemCardInfo{}
if err := json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
return "", err
}
exValue.FaceType = faceValue
res, err := json.Marshal(&exValue)
return string(res), err
}
func GetCompleteRedeemExValue(exValueStr string, faceValue string) (exValue supplier.RedeemCardInfo, err error) {
exValue = supplier.RedeemCardInfo{}
if err = json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
return exValue, err
}
exValue.FaceType = faceValue
return
}
func CompleteRechargeExValue(exValueStr string, faceValue string) (string, error) {
exValue := supplier.RechargeCardInfo{}
if err := json.Unmarshal([]byte(exValueStr), &exValue); err != nil {
return "", err
}
exValue.FaceType = faceValue
res, err := json.Marshal(&exValue)
return string(res), err
}
// NotifyUrlIsValid 判断回调地址是否符合规则
func NotifyUrlIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["notifyUrl"] == "" || len(convertor.ToString(c.Params["notifyUrl"])) == 0 {
c.Code = -1
c.Msg = "订单回调不能为空"
}
return c
}
// OsTypeIsValid 判断设备类型是否符合规则
func OsTypeIsValid(c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["osType"] == "" || len(convertor.ToString(c.Params["osType"])) == 0 {
c.Code = -1
c.Msg = "支付设备系统类型不能为空,默认填写\"1\"即可"
}
return c
}
func OrderPeriodIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderPeriod"] == "" || len(convertor.ToString(c.Params["orderPeriod"])) == 0 {
c.Code = -1
c.Msg = "订单过期时间不能为空,默认填写\"1\"即可"
}
return c
}
// OrderPriceIsValid 判断订单金额
func OrderPriceIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderPrice"] == "" || len(convertor.ToString(c.Params["orderPrice"])) == 0 {
c.Code = -1
c.Msg = "订单金额不能为空"
return c
}
a, err := strconv.ParseFloat(convertor.ToString(c.Params["orderPrice"]), 64)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("order price is invalid ", zap.Any("orderPrice", c.Params["orderPrice"]), zap.Error(err))
c.Code = -1
c.Msg = "订单金额非法"
}
c.OrderAmount = a
return c
}
// OrderIsValid 判断金额订单号是否为空或者有重复
func OrderIsValid(ctx context.Context, c *response.PayBaseResp) *response.PayBaseResp {
if c.Params["orderNo"] == "" || len(convertor.ToString(c.Params["orderNo"])) == 0 {
c.Code = -1
c.Msg = "商户订单号不能为空"
return c
}
return c
}
// IpIsWhite 判断ip是否在白名单中
func IpIsWhite() bool {
// TODO
return true
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +1,22 @@
package service
import (
"gateway/internal/utils"
"github.com/beego/beego/v2/core/logs"
"testing"
)
func TestCreateOrderNotifyInfo(t *testing.T) {
params := map[string]any{
"orderNo": "19044001vip88n29797005312", // 商户订单号
"orderPrice": "100.00",
"factPrice": "100.00",
"orderTime": "20250325131040",
"trxNo": "666e683460c9b9541bb984caff0416f1a4c",
"payKey": "kkkkcvbe5orl5mqs7385b9g0",
"statusCode": "1",
"failReason": "手动修正至成功",
}
sign := utils.GetMD5SignMF(params, "sssscvbe5orl5mqs7385b9gg")
logs.Info(sign)
}
package service
import (
"gateway/internal/utils"
"github.com/beego/beego/v2/core/logs"
"testing"
)
func TestCreateOrderNotifyInfo(t *testing.T) {
params := map[string]any{
"orderNo": "202506081821255349574555", // 商户订单号
"orderPrice": "10.00",
"factPrice": "10.00",
"orderTime": "20250608182213",
"trxNo": "666a193b2f0382248e385c0abb6da15f50",
"payKey": "kkkkd12l87bl5mqs73ef38o0",
"statusCode": "1",
"failReason": "卡号或密码不正确或已经使用完了",
}
sign := utils.GetMD5SignMF(params, "ssssd12l87bl5mqs73ef38og")
logs.Info(sign)
}

View File

@@ -1,105 +1,105 @@
package utils
import (
"context"
"gateway/internal/otelTrace"
"maps"
"sort"
"strings"
"github.com/duke-git/lancet/v2/convertor"
"go.uber.org/zap"
)
func GetMD5Sign(ctx context.Context, params map[string]any, keys []string, paySecret string) string {
sort.Strings(keys)
str := ""
for i := 0; i < len(keys); i++ {
k := keys[i]
if len(convertor.ToString(params[k])) == 0 || k == "sign" {
continue
}
str += k + "=" + convertor.ToString(params[k]) + "&"
}
str += "paySecret=" + paySecret
sign := GetMD5Upper(str)
return sign
}
func GetMD5SignLower(ctx context.Context, params map[string]any, keys []string, paySecret string) string {
return strings.ToLower(GetMD5Sign(ctx, params, keys, paySecret))
}
func Md5Verify(ctx context.Context, params map[string]any, paySecret string) bool {
//生成map一个copy
paramsCopy := make(map[string]any)
for k, v := range params {
paramsCopy[k] = v
}
sign := paramsCopy["sign"]
if sign == "" {
return false
}
signStr, ok := sign.(string)
if !ok {
return false
}
delete(paramsCopy, "sign")
keys := SortMap(paramsCopy)
tmpSign := GetMD5Sign(ctx, paramsCopy, keys, paySecret)
otelTrace.Logger.WithContext(ctx).Info("signStr=%s tmpStr=%s, %s", zap.String("signStr", tmpSign), zap.Any("tmpStr", sign), zap.Bool("sign!=tmpSign", tmpSign != signStr))
return strings.ToLower(tmpSign) == strings.ToLower(signStr)
}
func Md5MFVerify(ctx context.Context, params map[string]any, paySecret string) bool {
//生成map一个copy
paramsCopy := make(map[string]any)
maps.Copy(paramsCopy, params)
sign := paramsCopy["sign"]
if sign == "" {
return false
}
delete(paramsCopy, "sign")
delete(paramsCopy, "deviceId")
delete(paramsCopy, "ip")
tmpSign := GetMD5SignMF(paramsCopy, paySecret)
signStr, ok := sign.(string)
if !ok {
return false
}
otelTrace.Logger.WithContext(ctx).Info("signStr=%s tmpStr=%s, %s", zap.String("signStr", tmpSign), zap.Any("tmpStr", sign), zap.Bool("sign!=tmpSign", tmpSign != signStr))
return strings.EqualFold(strings.ToLower(tmpSign), strings.ToLower(signStr))
}
// Md5TMPMFVerify TODO: 兼容之前验证的代码
func Md5TMPMFVerify(ctx context.Context, params map[string]any, paySecret string) bool {
//生成map一个copy
paramsCopy := make(map[string]any)
for k, v := range params {
paramsCopy[k] = v
}
sign := paramsCopy["sign"]
if sign == "" {
return false
}
delete(paramsCopy, "sign")
delete(paramsCopy, "deviceId")
tmpSign := GetMD5SignMF(paramsCopy, paySecret)
otelTrace.Logger.WithContext(ctx).Info("signStr=%s tmpStr=%s, %s", zap.String("signStr", tmpSign), zap.Any("tmpStr", sign), zap.Bool("sign!=tmpSign", tmpSign != sign))
return tmpSign == sign
}
func GetMD5SignMF(params map[string]any, paySecret string) string {
strArr := SortMap(params)
signStr := ""
for i := 0; i < len(strArr); i++ {
k := strArr[i]
if len(convertor.ToString(params[k])) == 0 {
signStr += k
} else {
signStr += k + convertor.ToString(params[k])
}
}
signStr += paySecret
return GetMd5Lower(signStr)
}
package utils
import (
"context"
"gateway/internal/otelTrace"
"maps"
"sort"
"strings"
"github.com/duke-git/lancet/v2/convertor"
"go.uber.org/zap"
)
func GetMD5Sign(ctx context.Context, params map[string]any, keys []string, paySecret string) string {
sort.Strings(keys)
str := ""
for i := 0; i < len(keys); i++ {
k := keys[i]
if len(convertor.ToString(params[k])) == 0 || k == "sign" {
continue
}
str += k + "=" + convertor.ToString(params[k]) + "&"
}
str += "paySecret=" + paySecret
sign := GetMD5Upper(str)
return sign
}
func GetMD5SignLower(ctx context.Context, params map[string]any, keys []string, paySecret string) string {
return strings.ToLower(GetMD5Sign(ctx, params, keys, paySecret))
}
func Md5Verify(ctx context.Context, params map[string]any, paySecret string) bool {
//生成map一个copy
paramsCopy := make(map[string]any)
for k, v := range params {
paramsCopy[k] = v
}
sign := paramsCopy["sign"]
if sign == "" {
return false
}
signStr, ok := sign.(string)
if !ok {
return false
}
delete(paramsCopy, "sign")
keys := SortMap(paramsCopy)
tmpSign := GetMD5Sign(ctx, paramsCopy, keys, paySecret)
otelTrace.Logger.WithContext(ctx).Info("signStr=%s tmpStr=%s, %s", zap.String("signStr", tmpSign), zap.Any("tmpStr", sign), zap.Bool("sign!=tmpSign", tmpSign != signStr))
return strings.ToLower(tmpSign) == strings.ToLower(signStr)
}
func Md5MFVerify(ctx context.Context, params map[string]any, paySecret string) bool {
//生成map一个copy
paramsCopy := make(map[string]any)
maps.Copy(paramsCopy, params)
sign := paramsCopy["sign"]
if sign == "" {
return false
}
delete(paramsCopy, "sign")
delete(paramsCopy, "deviceId")
delete(paramsCopy, "ip")
tmpSign := GetMD5SignMF(paramsCopy, paySecret)
signStr, ok := sign.(string)
if !ok {
return false
}
otelTrace.Logger.WithContext(ctx).Info("signStr=%s tmpStr=%s, %s", zap.String("signStr", tmpSign), zap.Any("tmpStr", sign), zap.Bool("sign!=tmpSign", tmpSign != signStr))
return strings.EqualFold(strings.ToLower(tmpSign), strings.ToLower(signStr))
}
// Md5TMPMFVerify TODO: 兼容之前验证的代码
func Md5TMPMFVerify(ctx context.Context, params map[string]any, paySecret string) bool {
//生成map一个copy
paramsCopy := make(map[string]any)
for k, v := range params {
paramsCopy[k] = v
}
sign := paramsCopy["sign"]
if sign == "" {
return false
}
delete(paramsCopy, "sign")
delete(paramsCopy, "deviceId")
tmpSign := GetMD5SignMF(paramsCopy, paySecret)
otelTrace.Logger.WithContext(ctx).Info("signStr=%s tmpStr=%s, %s", zap.String("signStr", tmpSign), zap.Any("tmpStr", sign), zap.Bool("sign!=tmpSign", tmpSign != sign))
return tmpSign == sign
}
func GetMD5SignMF(params map[string]any, paySecret string) string {
strArr := SortMap(params)
signStr := ""
for i := 0; i < len(strArr); i++ {
k := strArr[i]
if len(convertor.ToString(params[k])) == 0 {
signStr += k
} else {
signStr += k + convertor.ToString(params[k])
}
}
signStr += paySecret
return GetMd5Lower(signStr)
}