Merge pull request 'feat-IRONFANS-56-Robin' (#140) from feat-IRONFANS-56-Robin into test

Reviewed-on: http://121.41.31.146:3000/wishpal_ironfan/service/pulls/140
This commit is contained in:
chenhao 2024-02-27 01:51:28 +08:00
commit 71f7764e07
19 changed files with 287 additions and 67 deletions

View File

@ -31,6 +31,7 @@ const (
PayTypeAlipayH5 = "alipay_h5" // 支付宝 h5
PayTypeWxpayNative = "wxpay_native" // 微信 native
PayTypeWxpayJsapi = "wxpay_jsapi" // 微信 jsapi
PayTypeWxpayH5 = "wxpay_h5" // 微信支付 h5
)
const (
@ -66,7 +67,8 @@ type CreateOrderData struct {
AlipayParamStr string `json:"alipay_param_str"` // 支付宝 app支付参数
AlipayH5ParamStr string `json:"alipay_h5_param_str"` // 支付宝 h5支付参数
WxpayNativeParamStr string `json:"wxpay_native_param_str"` // 微信支付 native支付参数
WxpayJsapiParamObj wxpaycli.JsapiPayResp `json:"wxpay_jsapi_param_obj"` // 微信支付 native
WxpayJsapiParamObj wxpaycli.JsapiPayResp `json:"wxpay_jsapi_param_obj"` // 微信支付 jsapi支付参数
WxpayH5ParamStr string `json:"wxpay_h5_param_str"` // 微信支付 h5支付参数
}
// 预解锁联系方式
@ -150,6 +152,7 @@ type H5DirectUnlockWechatData struct {
AlipayH5ParamStr string `json:"alipay_h5_param_str"` // 支付宝 h5支付参数
WxpayNativeParamStr string `json:"wxpay_native_param_str"` // 微信支付 native支付参数
WxpayJsapiParamObj wxpaycli.JsapiPayResp `json:"wxpay_jsapi_param_obj"` // 微信支付 native
WxpayH5ParamStr string `json:"wxpay_h5_param_str"` // 微信支付 h5支付参数
}
// 支付宝回调参数

View File

@ -5,6 +5,7 @@ import (
"service/api/consts"
bannerproto "service/api/proto/banner/proto"
catalogproto "service/api/proto/catalog/proto"
"service/bizcommon/common"
"service/bizcommon/util"
"strconv"
"time"
@ -1060,6 +1061,102 @@ func (m *Mongo) GetAccountCount(ctx *gin.Context, req *accountproto.OpCountReq)
return count, err
}
func (m *Mongo) GetLastHourNewUserFromAndroidCount(ctx *gin.Context, req *accountproto.OpCountReq) (int64, error) {
col := m.getColAccount()
filterInClause := []qmgo.M{}
if req.CtLowerBound != nil {
filterInClause = append(filterInClause, qmgo.M{
"ct": qmgo.M{
"$gte": util.DerefInt64(req.CtLowerBound),
},
})
}
if req.CtUpperBound != nil {
filterInClause = append(filterInClause, qmgo.M{
"ct": qmgo.M{
"$lte": util.DerefInt64(req.CtUpperBound),
},
})
}
if len(filterInClause) == 0 {
return 0, nil
}
filter := qmgo.M{
"$and": filterInClause,
"dev_type": common.DeviceTypeAndroid,
}
count, err := col.Find(ctx, filter).Count()
return count, err
}
func (m *Mongo) GetLastHourNewUserFromIosCount(ctx *gin.Context, req *accountproto.OpCountReq) (int64, error) {
col := m.getColAccount()
filterInClause := []qmgo.M{}
if req.CtLowerBound != nil {
filterInClause = append(filterInClause, qmgo.M{
"ct": qmgo.M{
"$gte": util.DerefInt64(req.CtLowerBound),
},
})
}
if req.CtUpperBound != nil {
filterInClause = append(filterInClause, qmgo.M{
"ct": qmgo.M{
"$lte": util.DerefInt64(req.CtUpperBound),
},
})
}
if len(filterInClause) == 0 {
return 0, nil
}
filter := qmgo.M{
"$and": filterInClause,
"dev_type": common.DeviceTypeIos,
}
count, err := col.Find(ctx, filter).Count()
return count, err
}
func (m *Mongo) GetLastHourNewUserFromH5Count(ctx *gin.Context, req *accountproto.OpCountReq) (int64, error) {
col := m.getColAccount()
filterInClause := []qmgo.M{}
if req.CtLowerBound != nil {
filterInClause = append(filterInClause, qmgo.M{
"ct": qmgo.M{
"$gte": util.DerefInt64(req.CtLowerBound),
},
})
}
if req.CtUpperBound != nil {
filterInClause = append(filterInClause, qmgo.M{
"ct": qmgo.M{
"$lte": util.DerefInt64(req.CtUpperBound),
},
})
}
if len(filterInClause) == 0 {
return 0, nil
}
filter := qmgo.M{
"$and": filterInClause,
"dev_type": common.DeviceTypeH5,
}
count, err := col.Find(ctx, filter).Count()
return count, err
}
// vericode相关
func (m *Mongo) CreateVeriCode(ctx *gin.Context, vericode *dbstruct.VeriCode) error {
col := m.getColVeriCode()

View File

@ -25,6 +25,7 @@ import (
vericodeproto "service/api/proto/vericode/proto"
"service/apollostruct"
businessvalidator "service/app/mix/service/business_validator"
"service/bizcommon/common"
"service/bizcommon/util"
"service/dbstruct"
"service/library/apollo"
@ -127,8 +128,11 @@ func (s *Service) ApiLoginByVeriCode(ctx *gin.Context, req *loginproto.ApiLoginB
login, account, vericode, ec = s.ApiLoginByVeriCodeBusinessValidate(ctx, req)
// 2.如果错误码是登录信息不存在,则判断为首次登录,将创建用户信息
if req.Channel == "h5" {
req.DevType = common.DeviceTypeH5
}
if ec == errcode.ErrCodeLoginNotExist {
login, account, ec = s.utilRegisterUser(ctx, &req.MobilePhoneInfoComponent, req.Inviter)
login, account, ec = s.utilRegisterUser(ctx, &req.MobilePhoneInfoComponent, req.Inviter, req.DevType)
if ec != errcode.ErrCodeLoginSrvOk {
logger.Error("utilRegisterUser failed")
ec = errcode.ErrCodeLoginRegisterUserFail

View File

@ -163,6 +163,25 @@ func (p *Account) OpCount(ctx *gin.Context, req *accountproto.OpCountReq) (int64
return count, err
}
func (p *Account) OpCountLastHourNewUserSource(ctx *gin.Context, req *accountproto.OpCountReq) (int64, int64, int64, error) {
androidCount, err := p.store.GetLastHourNewUserFromAndroidCount(ctx, req)
if err != nil {
logger.Error("GetLastHourNewUserSourceCount fail, err: %v", err)
return 0, 0, 0, err
}
iosCount, err := p.store.GetLastHourNewUserFromIosCount(ctx, req)
if err != nil {
logger.Error("GetLastHourNewUserFromIosCount fail, err: %v", err)
return 0, 0, 0, err
}
h5Count, err := p.store.GetLastHourNewUserFromH5Count(ctx, req)
if err != nil {
logger.Error("GetLastHourNewUserFromH5Count fail, err: %v", err)
return 0, 0, 0, err
}
return androidCount, iosCount, h5Count, err
}
func (p *Account) GetInviterMid(ctx *gin.Context, mid int64) (int64, error) {
inviterMid := int64(0)
userAcct, err := p.OpListByMid(ctx, &accountproto.OpListByMidReq{

View File

@ -98,6 +98,7 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data
alipayH5ParamStr string
wxpayNativeParamStr string
wxpayJsapiParamObj wxpaycli.JsapiPayResp
wxpayH5ParamStr string
)
defer func() {
@ -241,6 +242,25 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data
return
}
req.Oid3 = wxpayCli.AppId
case vasproto.PayTypeWxpayH5:
wxpayCli := wxpaycli.GetDefaultWxpayClient()
h5PayParam := &wxpaycli.H5PayParam{
Description: product.Subject,
OutTradeNo: orderId,
TotalAmount: product.RealPrice,
TimeOutSeconds: 900,
Cip: ctx.ClientIP(),
}
// 给个默认ip
if len(h5PayParam.Cip) <= 0 {
h5PayParam.Cip = "112.124.18.6"
}
wxpayH5ParamStr, err = wxpayCli.H5Pay(ctx, h5PayParam)
if err != nil {
logger.Error("wxpay H5Pay fail, req: %v, h5PayParam: %v, err: %v", util.ToJson(req), util.ToJson(h5PayParam), err)
return
}
req.Oid3 = wxpayCli.AppId
}
// 添加订单
@ -284,6 +304,7 @@ func (v *Vas) CreateOrder(ctx *gin.Context, req *vasproto.CreateOrderReq) (data
AlipayH5ParamStr: alipayH5ParamStr,
WxpayNativeParamStr: wxpayNativeParamStr,
WxpayJsapiParamObj: wxpayJsapiParamObj,
WxpayH5ParamStr: wxpayH5ParamStr,
}
return
}
@ -1383,7 +1404,7 @@ func (v *Vas) GetAddWechatCoinOrders(ctx *gin.Context, mid int64, offset, limit
statusList := make([]int32, 0)
switch tab {
case vasproto.AddWechatListTabWait:
statusList = []int32{dbstruct.VasCoinOrderStatusNotFill, dbstruct.VasCoinOrderStatusWaitDeal, dbstruct.VasCoinOrderStatusRefund}
statusList = []int32{dbstruct.VasCoinOrderStatusNotFill, dbstruct.VasCoinOrderStatusWaitDeal}
case vasproto.AddWechatListTabFinish:
statusList = []int32{dbstruct.VasCoinOrderStatusDeal, dbstruct.VasCoinOrderStatusFinish, dbstruct.VasCoinOrderStatusRefund}
}
@ -1554,6 +1575,7 @@ func (v *Vas) H5DirectUnlockWechat(ctx *gin.Context, req *vasproto.H5DirectUnloc
AlipayH5ParamStr: cData.AlipayH5ParamStr,
WxpayNativeParamStr: cData.WxpayNativeParamStr,
WxpayJsapiParamObj: cData.WxpayJsapiParamObj,
WxpayH5ParamStr: cData.WxpayH5ParamStr,
}
return
}
@ -1947,6 +1969,8 @@ func (v *Vas) WithdrawApply(ctx *gin.Context, req *vasproto.WithdrawApplyReq) (t
// 2000元以下直接操作
if money <= 200000 {
alipayCli := alipaycli.GetAlipayClientByAppId(alipaycli.AppIdXinYiDaoLe)
// 更改状态
err = v.store.UpdateWithdrawOrderStatus(ctx, tx, orderId, dbstruct.VasWithdrawOrderStatusInit, dbstruct.VasWithdrawOrderStatusAuto)
if err != nil {
@ -1981,7 +2005,7 @@ func (v *Vas) WithdrawApply(ctx *gin.Context, req *vasproto.WithdrawApplyReq) (t
AlipayLoginId: alipayId,
AlipayName: alipayName,
}
transferResp, err = alipaycli.GetDefaultAlipayClient().UniTransfer(ctx, transferParam)
transferResp, err = alipayCli.UniTransfer(ctx, transferParam)
if err != nil {
logger.Error("UniTransfer fail, param: %v, err: %v", util.ToJson(transferParam), err)
return

View File

@ -540,7 +540,7 @@ func (s *Service) OpLoginByVeriCode(ctx *gin.Context, req *loginproto.OpLoginByV
// 2.如果错误码是登录信息不存在,则判断为首次登录,将创建用户信息
if ec == errcode.ErrCodeLoginNotExist {
login, account, ec = s.utilRegisterUser(ctx, &req.MobilePhoneInfoComponent, req.Inviter)
login, account, ec = s.utilRegisterUser(ctx, &req.MobilePhoneInfoComponent, req.Inviter, req.BaseRequest.DevType)
if ec != errcode.ErrCodeLoginSrvOk {
logger.Error("utilRegisterUser failed")
ec = errcode.ErrCodeLoginRegisterUserFail

View File

@ -30,7 +30,7 @@ import (
// 不向外暴露的辅助公共函数
// 注册账户
func (s *Service) utilRegisterUser(ctx *gin.Context, req *loginproto.MobilePhoneInfoComponent, inviter *int64) (login *dbstruct.Login, account *dbstruct.Account, ec errcode.ErrCode) {
func (s *Service) utilRegisterUser(ctx *gin.Context, req *loginproto.MobilePhoneInfoComponent, inviter *int64, devType int32) (login *dbstruct.Login, account *dbstruct.Account, ec errcode.ErrCode) {
var err error
inviterUserId := int64(0)
@ -71,6 +71,7 @@ func (s *Service) utilRegisterUser(ctx *gin.Context, req *loginproto.MobilePhone
account.RegionCode = goproto.String(req.RegionCode)
account.PhoneHash = goproto.String(req.PhoneHash)
account.IsAMember = goproto.Int64(0)
account.DevType = goproto.Int32(devType)
if inviterUserId != 0 {
account.Inviter = goproto.Int64(inviterUserId)
}

View File

@ -107,6 +107,12 @@ func (s *CronService) CreateDailyStatement(ctx context.Context, param *xxl.RunRe
return fmt.Sprintf("_DefaultVas GetOrderCountByStatus fail : %v", err)
}
//获取用户注册来源
androidCount, iosCount, h5Count, err := _DefaultAccount.OpCountLastHourNewUserSource(&gin.Context{}, &accountproto.OpCountReq{
CtLowerBound: goproto.Int64(startTimeStamp),
CtUpperBound: goproto.Int64(endTimeStamp),
})
finishedOrderCount := int32(0)
allOrderCount := int32(0)
for _, orderCount := range orderCounts {
@ -117,12 +123,15 @@ func (s *CronService) CreateDailyStatement(ctx context.Context, param *xxl.RunRe
}
dailyStatement := &dbstruct.DailyStatement{
H5CallCount: goproto.Int64(int64(count)),
RegisteredUserCount: goproto.Int64(accountCount),
OrderCreatedCount: goproto.Int64(int64(allOrderCount)),
OrderFinishedCount: goproto.Int64(int64(finishedOrderCount)),
StartTime: goproto.Int64(startTimeStamp),
EndTime: goproto.Int64(endTimeStamp),
H5CallCount: goproto.Int64(int64(count)),
RegisteredUserCount: goproto.Int64(accountCount),
OrderCreatedCount: goproto.Int64(int64(allOrderCount)),
OrderFinishedCount: goproto.Int64(int64(finishedOrderCount)),
LastHourNewUserCountFromAndroid: goproto.Int64(androidCount),
LastHourNewUserCountFromIos: goproto.Int64(iosCount),
LastHourNewUserCountFromH5: goproto.Int64(h5Count),
StartTime: goproto.Int64(startTimeStamp),
EndTime: goproto.Int64(endTimeStamp),
}
err = _DefaultDailyStatement.OpCreate(&gin.Context{}, &daily_statementproto.OpCreateReq{
DailyStatement: dailyStatement,

View File

@ -106,3 +106,10 @@ func BytesToString(b []byte) (s string) {
_sptr.Len = _bptr.Len
return s
}
func UnescapeJsonStr(s string) string {
s = strings.ReplaceAll(s, "\\u003c", "<")
s = strings.ReplaceAll(s, "\\u003e", ">")
s = strings.ReplaceAll(s, "\\u0026", "&")
return s
}

View File

@ -22,6 +22,7 @@ type Account struct {
DiamondNum *int64 `json:"diamond_num" bson:"diamond_num"` // 钻石数量
Inviter *int64 `json:"inviter" bson:"inviter"` // 邀请人user_id
IsAMember *int64 `json:"is_a_member" bson:"is_a_member"` // 是否是会员0-否1-是
DevType *int32 `bson:"dev_type"` // 注册来源
Latitude *float64 `bson:"latitude"` // 纬度
Longitude *float64 `bson:"longitude"` // 经度
Ct *int64 `json:"ct" bson:"ct"` // 创建时间

View File

@ -1,15 +1,18 @@
package dbstruct
type DailyStatement struct {
Id *int64 `json:"id" bson:"_id"` // 每日报表id
H5CallCount *int64 `json:"h5_call_count" bson:"h5_call_count"` // H5接口调用总量
RegisteredUserCount *int64 `json:"registered_user_count" bson:"registered_user_count"` // 注册用户总量
OrderCreatedCount *int64 `json:"order_created_count" bson:"order_created_count"` // 订单创建总量
OrderFinishedCount *int64 `json:"order_finished_count" bson:"order_finished_count"` // 订单完成总量
StartTime *int64 `json:"start_time" bson:"start_time"` // 起始时间
EndTime *int64 `json:"end_time" bson:"end_time"` // 结束时间
Ct *int64 `json:"ct" bson:"ct"` // 创建时间
Ut *int64 `json:"ut" bson:"ut"` // 更新时间
DelFlag *int64 `json:"del_flag" bson:"del_flag"` // 删除标记
Id *int64 `json:"id" bson:"_id"` // 每日报表id
H5CallCount *int64 `json:"h5_call_count" bson:"h5_call_count"` // H5接口调用总量
RegisteredUserCount *int64 `json:"registered_user_count" bson:"registered_user_count"` // 注册用户总量
OrderCreatedCount *int64 `json:"order_created_count" bson:"order_created_count"` // 订单创建总量
OrderFinishedCount *int64 `json:"order_finished_count" bson:"order_finished_count"` // 订单完成总量
LastHourNewUserCountFromAndroid *int64 `json:"last_hour_new_user_count_from_android" bson:"last_hour_new_user_count_from_android"` // 安卓注册总量
LastHourNewUserCountFromIos *int64 `json:"last_hour_new_user_count_from_ios" bson:"last_hour_new_user_count_from_ios"` // ios注册总量
LastHourNewUserCountFromH5 *int64 `json:"last_hour_new_user_count_from_h5" bson:"last_hour_new_user_count_from_h5"` // h5注册总量
StartTime *int64 `json:"start_time" bson:"start_time"` // 起始时间
EndTime *int64 `json:"end_time" bson:"end_time"` // 结束时间
Ct *int64 `json:"ct" bson:"ct"` // 创建时间
Ut *int64 `json:"ut" bson:"ut"` // 更新时间
DelFlag *int64 `json:"del_flag" bson:"del_flag"` // 删除标记
}

View File

@ -112,9 +112,9 @@ server_info:
file_server_domain_name: "https://file.tiefen.fun/"
xxl_job:
server_addr: "http://127.0.0.1:9800/xxl-job-admin"
server_addr: "http://172.16.0.174:9800/xxl-job-admin"
access_token: "default_token"
executor_ip: "127.0.0.1"
executor_ip: "172.16.0.177"
executor_port: "9801"
registry_key: "golang-jobs-executor"
log_path: "/app/ironfan/log/xxl_job/"

View File

@ -42,9 +42,6 @@ func Run(batchId string) (successNum int, failNum int, err error) {
return 0, 0, nil
}
// 上锁
defaultImageAuditTaskScheduler.lock()
logger.Info("Image audit batch started, batchId : %v, task number : %v", batchId, len(imageaudittasks))
// 1.构建批量任务控制块初始化必要的actionMap、填充送审image等信息
ctrlBlock := NewImageAuditTaskBatchControlBlock(imageaudittasks, batchId)
@ -64,6 +61,7 @@ func Run(batchId string) (successNum int, failNum int, err error) {
ConnectTimeout: tea.Int(30000),
}
_result, err := defaultImageAuditClient.ScanImageAdvance(req, runtime)
logger.Info("Receive the response from ScanImageAdvance: %v", _result.String())
if err != nil {
if _t, ok := err.(*tea.SDKError); ok {
logger.Error("ScanImageAdvance fail, errinfo : %v", util.DerefString(_t.Data))
@ -76,8 +74,6 @@ func Run(batchId string) (successNum int, failNum int, err error) {
// 4.处理应答
err = handleScanImageResponse(ctrlBlock, _result)
// 解锁
defaultImageAuditTaskScheduler.unLock()
successNum = len(imageaudittasks)
return
}
@ -119,37 +115,45 @@ func handleScanImageResponse(ctrlBlock *ImageAuditTaskBatchControlBlock, resp *i
img2taskIndexMap := ctrlBlock.Img2taskIndexMap
actionMap := ctrlBlock.ActionMap
for i, result := range results {
logger.Info("Handling %vs result...", i)
isTaskCompleted := false
isActionCompleted := false
action := &ImageAuditAction{}
// 1.dataId是imageaudit表主键Id, 唯一标识一次对单张图片的图像审核
logger.Info("Getting dataId...")
dataId := util.DerefString(result.DataId)
// 2.立即在imageaudit-imageaudit中更新该次审核结果
logger.Info("Handling its audit record...")
pass, err := handleImageAudit(dataId, result)
if err != nil {
logger.Error("handleImageAudit fail: %v", err)
}
// 3.取出task
logger.Info("Retriving its audit task...")
taskIndex := img2taskIndexMap[i]
task := taskCtrlBlocks[taskIndex]
// 4.在task中记录本分片结果并累积已到达的分片数直到所有分片到达决定该任务是否成功(非分片任务分片数为1)
logger.Info("Recording it to task...")
isTaskCompleted = handleTask(task, pass)
// 5.通过task的actionId去actionId-[]*task的map查出本批次对该字段的动作链更新其中关于自己的状态
logger.Info("Recording the task result...")
if isTaskCompleted {
isActionCompleted, action = handleTaskAction(task, actionMap)
}
// 6.等待所有动作链元素均已抵达,判定本批次对该字段的操作是否成功
logger.Info("Recording the action result...")
if isActionCompleted {
if err = finalizeTask(action); err != nil {
logger.Error("finalizeTask fail: %v", err)
}
}
logger.Info("%vs result handled...", i)
}
return
}

View File

@ -10,29 +10,14 @@ var defaultImageAuditTaskScheduler *ImageAuditTaskScheduler
// 图像审核任务调度器
type ImageAuditTaskScheduler struct {
// 同步标志
batchFlag chan bool // 批处理同步标志
// 状态记录
batchId string // 当前批次号
}
func initScheduler(cfg *configcenter.ImageAuditConfig) {
defaultImageAuditTaskScheduler = &ImageAuditTaskScheduler{
batchFlag: make(chan bool, 1),
batchId: genereteBatchId(),
batchId: genereteBatchId(),
}
defaultImageAuditTaskScheduler.batchFlag <- true
}
// 批处理上锁
func (s *ImageAuditTaskScheduler) lock() {
<-s.batchFlag
}
// 批处理解锁
func (s *ImageAuditTaskScheduler) unLock() {
s.batchFlag <- true
}
// 生成批次号

View File

@ -10,29 +10,14 @@ var defaultTextAuditTaskScheduler *TextAuditTaskScheduler
// 文字审核任务调度器
type TextAuditTaskScheduler struct {
// 缓冲池、同步标志
batchFlag chan bool // 批处理同步标志
// 状态记录
batchId string // 当前批次号
}
func initScheduler(cfg *configcenter.TextAuditConfig) {
defaultTextAuditTaskScheduler = &TextAuditTaskScheduler{
batchFlag: make(chan bool, 1),
batchId: genereteBatchId(),
batchId: genereteBatchId(),
}
defaultTextAuditTaskScheduler.batchFlag <- true
}
// 批处理上锁
func (s *TextAuditTaskScheduler) lock() {
<-s.batchFlag
}
// 批处理解锁
func (s *TextAuditTaskScheduler) unLock() {
s.batchFlag <- true
}
// 生成批次号

View File

@ -39,9 +39,6 @@ func Run(batchId string) (successNum int, failNum int, err error) {
return 0, 0, nil
}
// 上锁
defaultTextAuditTaskScheduler.lock()
logger.Info("Text audit batch started, batchId : %v, task number : %v", batchId, len(textaudittasks))
// 1.构建批量任务控制块初始化必要的actionMap、填充送审text等信息
ctrlBlock := NewTextAuditTaskBatchControlBlock(textaudittasks, batchId)
@ -68,8 +65,6 @@ func Run(batchId string) (successNum int, failNum int, err error) {
// 4.处理应答
err = handleScanTextResponse(ctrlBlock, _result)
// 解锁
defaultTextAuditTaskScheduler.unLock()
successNum = len(textaudittasks)
return
}

View File

@ -25,7 +25,7 @@ const (
var allAlipayClients = map[string]*AlipayClient{}
func GetDefaultAlipayClient() *AlipayClient {
return allAlipayClients[AppIdXinYiDaoLe]
return allAlipayClients[AppIdMiYuanTianShi]
}
func GetAlipayClientByAppId(appId string) *AlipayClient {

View File

@ -242,3 +242,47 @@ func rsaSign(prvkey []byte, hash crypto.Hash, data []byte) ([]byte, error) {
}
return rsa.SignPKCS1v15(cryptorand.Reader, privateKey.(*rsa.PrivateKey), hash, hashed)
}
// 微信支付 h5支付
type H5PayParam struct {
Description string
OutTradeNo string // 商家订单id我们自己的订单id
TotalAmount int64 // 金额,单位:分
TimeOutSeconds int // 订单有效时间,单位:秒
Cip string // 客户端ip
}
func (c *WxpayClient) H5Pay(ctx context.Context, param *H5PayParam) (wxpayH5ParamStr string, err error) {
if param.TimeOutSeconds <= 0 {
param.TimeOutSeconds = DefaultOrderTimeoutSeconds
}
bm := gopay.BodyMap{
"appid": c.AppId,
"description": param.Description,
"out_trade_no": param.OutTradeNo,
"time_expire": time.Now().Add(time.Second * time.Duration(param.TimeOutSeconds)).Format(time.RFC3339),
"notify_url": c.NotifyUrl,
"amount": gopay.BodyMap{
"total": param.TotalAmount,
"currency": "CNY",
},
"scene_info": gopay.BodyMap{
"payer_client_ip": param.Cip,
"h5_info": gopay.BodyMap{
"type": "Wap",
},
},
}
resp, err := c.clientV3.V3TransactionH5(ctx, bm)
if err != nil {
return
}
if resp.Code != wxpayv3.Success {
logger.Info("wxpayv3 NativePay fail, code: %v, error: %v, response: %v", resp.Code, resp.Error, util.ToJson(resp.Response))
return
}
wxpayH5ParamStr = resp.Response.H5Url
logger.Info("wxpayv3 H5 success, code: %v, error: %v, response: %v", resp.Code, resp.Error, util.ToJson(resp.Response))
return
}

View File

@ -1,7 +1,9 @@
package wxpaycli
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"service/app/mix/conf"
@ -74,3 +76,40 @@ func TestWxpayClient_JsapiPay(t *testing.T) {
}
t.Log(util.ToJson(r))
}
type Track struct {
XmlRequest string `json:"xmlRequest"`
}
func (t *Track) JSON() ([]byte, error) {
buffer := &bytes.Buffer{}
encoder := json.NewEncoder(buffer)
// encoder.SetEscapeHTML(false)
err := encoder.Encode(t)
return buffer.Bytes(), err
}
func AT() {
message := Track{}
message.XmlRequest = "<car><mirror>XML</mirror></car>"
fmt.Println("Before Marshal", message)
messageJSON, _ := message.JSON()
fmt.Println("After marshal", string(messageJSON))
}
func TestWxpayClient_H5Pay(t *testing.T) {
cli := GetDefaultWxpayClient()
resp, err := cli.H5Pay(context.Background(), &H5PayParam{
Description: "hello",
OutTradeNo: idgenerator.GenOrderId(),
TotalAmount: 1,
TimeOutSeconds: 3600 * 24,
Cip: "223.104.41.0",
})
if err != nil {
t.Log(err.Error())
return
}
t.Log(resp)
}