feat(supplier): 添加瓦文卡券查询功能

- 新增 waveCard 方法,实现瓦文卡券余额查询
- 通过验证码图像识别实现自动验证码处理
- 完善查询失败及错误日志记录
- 添加对应单元测试覆盖 waveCard 功能
- 更新第三方依赖版本,提升性能与安全
- 升级 go-redis、zap 和其他 go.mod 依赖版本
- 重构鲁班卡密发送相关代码,使用 resty 替代 httplib
- 优化鲁班回调请求及返回值处理逻辑
- 调整 OCRClient 单例初始化方式,保证线程安全
- 修正 Base64Decode 函数注释规范为驼峰形式
This commit is contained in:
danial
2025-12-02 18:16:49 +08:00
parent 275bbac1da
commit 59cd2fe334
9 changed files with 195 additions and 49 deletions

View File

@@ -1 +1 @@
golang 1.25.2
golang 1.25.3

14
go.mod
View File

@@ -14,11 +14,11 @@ require (
github.com/forgoer/openssl v1.8.0
github.com/go-resty/resty/v2 v2.16.5
github.com/go-sql-driver/mysql v1.9.3
github.com/go-stomp/stomp/v3 v3.1.3
github.com/go-stomp/stomp/v3 v3.1.5
github.com/google/uuid v1.6.0
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/prometheus/client_golang v1.23.2
github.com/redis/go-redis/v9 v9.14.0
github.com/redis/go-redis/v9 v9.17.2
github.com/shopspring/decimal v1.4.0
github.com/stretchr/testify v1.11.1
github.com/widuu/gojson v0.0.0-20170212122013-7da9d2cd949b
@@ -34,7 +34,7 @@ require (
go.opentelemetry.io/otel/sdk/log v0.14.0
go.opentelemetry.io/otel/sdk/metric v1.38.0
go.opentelemetry.io/otel/trace v1.38.0
go.uber.org/zap v1.27.0
go.uber.org/zap v1.27.1
golang.org/x/exp v0.0.0-20250911091902-df9299821621
)
@@ -69,10 +69,10 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/arch v0.21.0 // indirect
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.31.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250922171735-9219d122eba9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250922171735-9219d122eba9 // indirect
google.golang.org/grpc v1.75.1 // indirect

28
go.sum
View File

@@ -48,8 +48,8 @@ github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptd
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-stomp/stomp/v3 v3.1.3 h1:5/wi+bI38O1Qkf2cc7Gjlw7N5beHMWB/BxpX+4p/MGI=
github.com/go-stomp/stomp/v3 v3.1.3/go.mod h1:ztzZej6T2W4Y6FlD+Tb5n7HQP3/O5UNQiuC169pIp10=
github.com/go-stomp/stomp/v3 v3.1.5 h1:Pikz1OSusmSKUm5mRKYfXQZaDatfZ+EnBBA1JJ2xENQ=
github.com/go-stomp/stomp/v3 v3.1.5/go.mod h1:ztzZej6T2W4Y6FlD+Tb5n7HQP3/O5UNQiuC169pIp10=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -96,8 +96,8 @@ github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9Z
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE=
github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI=
github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02 h1:v9ezJDHA1XGxViAUSIoO/Id7Fl63u6d0YmsAm+/p2hs=
@@ -162,8 +162,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw=
@@ -175,8 +175,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -196,8 +196,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -220,8 +220,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -240,8 +240,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"gateway/internal/otelTrace"
"sync"
"github.com/dubonzi/otelresty"
"github.com/go-resty/resty/v2"
@@ -17,8 +18,13 @@ import (
type OCRClient struct {
}
var ocrClient *OCRClient
func NewOCRClient() *OCRClient {
return &OCRClient{}
sync.OnceFunc(func() {
ocrClient = &OCRClient{}
})()
return ocrClient
}
type CalcInput struct {

View File

@@ -613,3 +613,90 @@ func (c *cardTypeQuery) jisuCard(ctx context.Context) (balance float64, err erro
}
return respData2.Data.Amount, nil
}
func (c *cardTypeQuery) waveCard(ctx context.Context) (balance float64, err error) {
webClient := resty.New().SetTimeout(time.Second * 5).SetRetryCount(3).SetHeaders(map[string]string{
"user-agent": useragent.GetUserAgentByPlatform(useragent.PlatformPhone),
}).OnBeforeRequest(func(c *resty.Client, request *resty.Request) error {
//proxy, _ := utils.GetProxy(ctx, utils.GenerateId(), "waveCard")
//if proxy != "" {
// c.SetProxy(proxy)
//}
return nil
})
otelresty.TraceClient(webClient)
for range 10 {
captchaResp, err2 := webClient.R().SetContext(ctx).Get("https://www.wavencard.com/ergouzi/auth/card_captcha.jpg")
if err2 != nil {
otelTrace.Logger.WithContext(ctx).Error("【瓦文】获取验证码失败", zap.Error(err))
continue
}
captchaRespData := struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
Img string `json:"img"`
Key string `json:"key"`
} `json:"data,omitempty"`
}{}
err = json.Unmarshal(captchaResp.Body(), &captchaRespData)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("【瓦文】获取验证码失败", zap.Error(err2))
continue
}
img, err2 := utils.Base64Decode(strings.ReplaceAll(captchaRespData.Data.Img, "data:image/png;base64,", ""))
if err2 != nil {
otelTrace.Logger.WithContext(ctx).Error("【瓦文】获取验证码失败", zap.Error(err2))
continue
}
captchaRes, err2 := client.NewOCRClient().Calc(ctx, &client.CalcInput{
File: img,
FileName: "card_captcha.png",
Category: "calc",
Length: 4,
})
if err2 != nil {
otelTrace.Logger.WithContext(ctx).Error("【瓦文】获取验证码失败", zap.Error(err2))
continue
}
response, err2 := webClient.R().SetContext(ctx).SetQueryParams(map[string]string{
"cardAccount": c.CardNo,
"cardPwd": c.CardPwd,
"verificationCode": captchaRes,
"captchaKey": captchaRespData.Data.Key,
"currentLang": "zh",
}).Get("https://www.wavencard.com/ergouzi/v_card/find_public_card_account")
if err2 != nil {
otelTrace.Logger.WithContext(ctx).Error("【瓦文】查询订单失败", zap.Error(err2))
continue
}
otelTrace.Logger.WithContext(ctx).Info("【瓦文】查询订单返回", zap.Any("resp", response.String()))
respData := struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
Amount string `json:"amount"`
Status string `json:"status"`
} `json:"data,omitempty"`
}{}
if err2 = json.Unmarshal(response.Body(), &respData); err2 != nil {
otelTrace.Logger.WithContext(ctx).Error("查卡错误", zap.Error(err2))
continue
}
if respData.Code != 200 {
return c.Balance, errors.New(respData.Msg)
}
amount, err2 := convertor.ToFloat(strings.TrimSpace(strings.ReplaceAll(respData.Data.Amount, "CNY", "")))
if err2 != nil {
otelTrace.Logger.WithContext(ctx).Error("【瓦文】查询订单失败", zap.Error(err2))
return c.Balance, errors.New("查卡失败")
}
if respData.Data.Status != "未使用" {
return c.Balance, errors.New("该卡已被其他用户绑定!")
}
return amount, nil
}
return c.Balance, errors.New("查卡失败")
}

View File

@@ -128,3 +128,16 @@ func Test_cardTypeQuery_jvnkaQuery(t *testing.T) {
otelTrace.Logger.WithContext(t.Context()).Info("查询结果", zap.Float64("balance", balance), zap.Error(err))
}
}
func Test_cardTypeQuery_waveCard(t *testing.T) {
cardQuery := cardTypeQuery{
Balance: 20,
CardNo: "w66444748872831218",
CardPwd: "57217792940",
QueryType: "outletcard",
}
for range 3 {
balance, err := cardQuery.waveCard(t.Context())
otelTrace.Logger.WithContext(t.Context()).Info("查询结果", zap.Float64("balance", balance), zap.Error(err))
}
}

View File

@@ -14,7 +14,6 @@ import (
"strings"
"time"
"github.com/beego/beego/v2/client/httplib"
"github.com/dubonzi/otelresty"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/maputil"
@@ -108,26 +107,18 @@ func (s *SendCardTaskTypeLuban) channelOne(ctx context.Context, orderItem OrderP
"card_no": task.CardInfo.CardNo,
"card_pwd": task.CardInfo.Data,
}
var response string
for range 3 {
request := httplib.NewBeegoRequestWithCtx(ctx, orderUrl, "GET").
SetTimeout(time.Second*5, time.Second*5).Retries(3).RetryDelay(3 * time.Second)
jsonBody, _ := json.Marshal(params)
request.Param("json", string(jsonBody))
request, _ = request.JSONBody(params)
response, err = request.String()
if err != nil {
return err
}
if !strings.Contains(response, "PROXY") && !strings.Contains(response, "RET") {
break
}
otelTrace.Logger.WithContext(ctx).Info("鲁班发送通知失败", zap.String("response", response), zap.Any("params", params), zap.String("orderUrl", orderUrl))
jsonBody, _ := json.Marshal(params)
client := resty.New().SetTimeout(time.Second * 5).SetTimeout(time.Second * 5)
otelresty.TraceClient(client)
response, err := client.R().SetContext(ctx).SetQueryParams(map[string]string{
"json": string(jsonBody),
}).Get("orderUrl")
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("请求失败", zap.Error(err))
return errors.New("请求失败")
}
otelTrace.Logger.WithContext(ctx).Info("鲁班回调通知", zap.String("response", response), zap.Any("params", params), zap.String("orderUrl", orderUrl))
otelTrace.Logger.WithContext(ctx).Info("回调", zap.String("response", response.String()), zap.Any("params", params), zap.String("orderUrl", orderUrl))
submitData := struct {
Code int64 `json:"code"`
@@ -135,8 +126,53 @@ func (s *SendCardTaskTypeLuban) channelOne(ctx context.Context, orderItem OrderP
Data string `json:"data"`
}{}
if err := json.Unmarshal([]byte(response), &submitData); err != nil {
otelTrace.Logger.WithContext(ctx).Error("转换返回值失败", zap.Error(err), zap.String("response", response))
if err = json.Unmarshal([]byte(response.String()), &submitData); err != nil {
otelTrace.Logger.WithContext(ctx).Error("转换返回值失败", zap.Error(err), zap.String("response", response.String()))
return errors.New("转换返回值失败")
}
if submitData.Code != 200 {
return errors.New(submitData.Msg)
}
return nil
}
func (s *SendCardTaskTypeLuban) channelTwo(ctx context.Context, orderItem OrderPoolItem, task SendCardTask) error {
otelTrace.Logger.WithContext(ctx).Info("处理任务", zap.Any("orderItem", orderItem), zap.Any("task", task))
query, err := url.Parse(orderItem.PayURL)
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("解析URL失败", zap.Error(err))
return errors.New("解析URL失败")
}
orderUrl := fmt.Sprintf("https://abc.pvcrr.com/baolingqiu/tdeal_order/postCardAndSecret")
params := map[string]any{
"tradeNo": query.Query().Get("tradeNo"),
"sign": query.Query().Get("sign"),
"card_no": task.CardInfo.CardNo,
"card_pwd": task.CardInfo.Data,
}
jsonBody, _ := json.Marshal(params)
client := resty.New().SetTimeout(time.Second * 5).SetTimeout(time.Second * 5)
otelresty.TraceClient(client)
response, err := client.R().SetContext(ctx).SetQueryParams(map[string]string{
"json": string(jsonBody),
}).Get("orderUrl")
if err != nil {
otelTrace.Logger.WithContext(ctx).Error("请求失败", zap.Error(err))
return errors.New("请求失败")
}
otelTrace.Logger.WithContext(ctx).Info("回调", zap.String("response", response.String()), zap.Any("params", params), zap.String("orderUrl", orderUrl))
submitData := struct {
Code int64 `json:"code"`
Msg string `json:"msg"`
Data string `json:"data"`
}{}
if err = json.Unmarshal([]byte(response.String()), &submitData); err != nil {
otelTrace.Logger.WithContext(ctx).Error("转换返回值失败", zap.Error(err), zap.String("response", response.String()))
return errors.New("转换返回值失败")
}
@@ -159,6 +195,10 @@ func (s *SendCardTaskTypeLuban) HandleSendCardTask(ctx context.Context, orderIte
err2 := (&SendCardTaskTypeFatSix{}).HandleSendCardTask(ctx, orderItem, task)
return err2
}
if strings.Contains(orderItem.PayURL, "abc.pvcrr.com") {
return s.channelTwo(ctx, orderItem, task)
}
return s.channelOne(ctx, orderItem, task)
}

View File

@@ -18,8 +18,8 @@ func TestSendCardTaskTypeLuban_CreateOrder(t *testing.T) {
orderId := utils.GenerateId()
params := map[string]any{
"mchId": "20000046",
"productId": "8011",
"mchId": "158",
"productId": "8010",
"currency": "cny",
"amount": 10 * 100,
"mchOrderNo": orderId,
@@ -30,11 +30,11 @@ func TestSendCardTaskTypeLuban_CreateOrder(t *testing.T) {
"version": "1.0",
}
params["sign"] = (&SendCardTaskTypeLuban{}).sign(t.Context(), params, "ROFMXGAPRQ7Y90AZXJL1DWR08S07SE3J5YXATKD9T8MVMBO0VICPYCFRNGWIVW8VFXZ9KYVISPIIWZAOEWDYCZEQ7CXFLMN82SHBQHTQZDBDPHL5OVJ5F4A4O7OUKC2R")
params["sign"] = (&SendCardTaskTypeLuban{}).sign(t.Context(), params, "POWTDMQWZOFYMFBADVCHPJNNQQQIUQSBQUZFZ37KF9NVPJBGN93PCMOESBWQPCSPABJXD5UIJZVYSJJ7UYW9WODJM4IURRSHPFLZBTNYIUGQEAPHFFINWZUU9RXI9WEK")
paramsStr := map[string]string{}
for k, v := range params {
paramsStr[k] = convertor.ToString(v)
}
response, _ := webClient.R().SetFormData(paramsStr).Post("http://gdxzf.info:56700/api/pay/create_order")
response, _ := webClient.R().SetFormData(paramsStr).Post("http://jiuzpay.xyz:56700/api/pay/create_order")
otelTrace.Logger.WithContext(t.Context()).Info("请求结果", zap.String("response", response.String()), zap.Any("params", params))
}

View File

@@ -29,7 +29,7 @@ func Base64Encode(raw []byte) string {
return t
}
// base64解码
// Base64Decode base64解码
func Base64Decode(raw string) ([]byte, error) {
return base64.StdEncoding.DecodeString(raw)
}