Compare commits
127 Commits
master
...
feature_41
Author | SHA1 | Date |
---|---|---|
|
f24a725cef | |
|
bdfd4c6b9c | |
|
595726bc60 | |
|
413f312ef6 | |
|
c13634ed08 | |
|
a54212d38c | |
|
bb9ff190c3 | |
|
78380d3a70 | |
|
9a413afa51 | |
|
7ed9cb048d | |
|
d76344573d | |
|
b0be00741f | |
|
966aba1dc4 | |
|
a6e8412654 | |
|
583aee88e2 | |
|
92733acffa | |
|
1630304f3d | |
|
50ef2fd13a | |
|
b3d8acba93 | |
|
8c05e8ff06 | |
|
5e0627a0f3 | |
|
f6bdfdf84c | |
|
6357d6706d | |
|
9b7f904108 | |
|
0755b14aa2 | |
|
1f7d46c110 | |
|
7f20bf6925 | |
|
39e64c8a22 | |
|
e5f50423ad | |
|
222522dc76 | |
|
9c725163c8 | |
|
ee912a204d | |
|
627e1c852c | |
|
342a247c67 | |
|
c9c7bdbc16 | |
|
aa43040aa2 | |
|
cb14c35aa9 | |
|
ebea5c52e0 | |
|
40dfffe31a | |
|
58f8cedb85 | |
|
d6bf4dd952 | |
|
7ed1ca131b | |
|
f225fc0f8c | |
|
30b83b3645 | |
|
62d050c02f | |
|
3061987dae | |
|
3d5e33fed0 | |
|
f85d6cc410 | |
|
bf1bc4b1a2 | |
|
d169ca7366 | |
|
0834171ea3 | |
|
514104a391 | |
|
ad56b5f0e5 | |
|
82ef285e7d | |
|
ca42c43bd2 | |
|
6ab982e874 | |
|
c79e316233 | |
|
c8a188e362 | |
|
75d68a3032 | |
|
e261a39cf5 | |
|
7a887833ad | |
|
68b9e16864 | |
|
b19576089c | |
|
4642ae73fe | |
|
6cfc7c0c06 | |
|
fa6b385209 | |
|
2d4d674145 | |
|
d979b7a966 | |
|
38f3e04352 | |
|
943c3401c6 | |
|
0d38872fa6 | |
|
2927161585 | |
|
e9d3dbece0 | |
|
3ed083bff6 | |
|
7ee666e459 | |
|
d488dddefd | |
|
daf5e2134f | |
|
6adcce1480 | |
|
74d1472a43 | |
|
e8576d67d9 | |
|
9f052435cc | |
|
548491c1f1 | |
|
50382f2c0a | |
|
71ccc46f23 | |
|
79723bd945 | |
|
0ac4feb07a | |
|
a7cf191437 | |
|
0f747c2578 | |
|
7dc1f9ef08 | |
|
50924acbc7 | |
|
3e7df62375 | |
|
65621d439b | |
|
39fb6d4d93 | |
|
5326e9c8d9 | |
|
490e2fa15f | |
|
b1a1a4cd50 | |
|
8ead5e11e2 | |
|
4d28483087 | |
|
13dce2d1c3 | |
|
aa1481b923 | |
|
b781a61f21 | |
|
6e6e01a823 | |
|
fb5c0e458b | |
|
b8e32f407a | |
|
f1bb1ad53b | |
|
b8da95788b | |
|
88b95cb67a | |
|
4842aa47a3 | |
|
a79b18d279 | |
|
f1ee9b4196 | |
|
bf4e24619d | |
|
92c1a3c230 | |
|
f8f0ac2913 | |
|
4d4338f178 | |
|
c1e354e4ab | |
|
28bd78ab7f | |
|
a056e2b26a | |
|
7a3823a2a7 | |
|
753b466605 | |
|
0b844afa5f | |
|
5a60a92f4b | |
|
dd3255e220 | |
|
4be80f228e | |
|
1a292ff5d3 | |
|
d343257e23 | |
|
95a050d64e | |
|
689b0f80db |
|
@ -0,0 +1,43 @@
|
|||
|
||||
## 使用官方Go镜像作为构建环境
|
||||
#FROM golang:1.21.0 AS builder
|
||||
#
|
||||
## 设置工作目录
|
||||
#WORKDIR /app
|
||||
#
|
||||
## 复制项目源码
|
||||
#COPY . .
|
||||
#
|
||||
## 复制go模块依赖文件
|
||||
#COPY go.mod go.sum ./
|
||||
#
|
||||
## 安装go模块依赖
|
||||
#RUN go env -w GOPROXY=https://goproxy.cn,direct
|
||||
#RUN go mod tidy
|
||||
#
|
||||
## 编译Go应用程序,生成静态链接的二进制文件
|
||||
#RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server .
|
||||
|
||||
# 创建最终镜像,用于运行编译后的Go程序
|
||||
FROM alpine
|
||||
|
||||
RUN echo 'http://mirrors.ustc.edu.cn/alpine/v3.5/main' > /etc/apk/repositories \
|
||||
&& echo 'http://mirrors.ustc.edu.cn/alpine/v3.5/community' >>/etc/apk/repositories \
|
||||
&& apk update && apk add tzdata \
|
||||
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
&& echo "Asia/Shanghai" > /etc/timezone \
|
||||
|
||||
ENV server = "admin"
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 将编译好的二进制文件从构建阶段复制到运行阶段
|
||||
COPY /server .
|
||||
#COPY --from=builder /app/server .
|
||||
COPY .env .
|
||||
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
# 设置容器启动时运行的命令
|
||||
ENTRYPOINT ["/app/server", "-a", "$server"]
|
|
@ -0,0 +1,28 @@
|
|||
GOHOSTOS:=$(shell go env GOHOSTOS)
|
||||
GOPATH:=$(shell go env GOPATH)
|
||||
VERSION=$(shell git describe --tags --always)
|
||||
|
||||
|
||||
ifeq ($(GOHOSTOS), windows)
|
||||
#the `find.exe` is different from `find` in bash/shell.
|
||||
#to see https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/find.
|
||||
#changed to use git-bash.exe to run find cli or other cli friendly, caused of every developer has a Git.
|
||||
#Git_Bash= $(subst cmd\,bin\bash.exe,$(dir $(shell where git)))
|
||||
Git_Bash=$(subst \,/,$(subst cmd\,bin\bash.exe,$(dir $(shell where git))))
|
||||
INTERNAL_PROTO_FILES=$(shell $(Git_Bash) -c "find internal -name *.proto")
|
||||
API_PROTO_FILES=$(shell $(Git_Bash) -c "find api -name *.proto")
|
||||
else
|
||||
INTERNAL_PROTO_FILES=$(shell find internal -name *.proto)
|
||||
API_PROTO_FILES=$(shell find api -name *.proto)
|
||||
endif
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
sh build/shell/build.sh
|
||||
|
||||
.PHONY: api
|
||||
api:
|
||||
sh build/shell/build.sh & build/bin/snow -a api
|
||||
|
||||
|
||||
|
|
@ -1,9 +1,317 @@
|
|||
package console
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/data"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/services/thirdpay/thirdpay_notify"
|
||||
"PaymentCenter/app/third/paymentService"
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/qit-team/snow-core/command"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func RegisterCommand(c *command.Command) {
|
||||
c.AddFunc("test", test)
|
||||
c.AddFunc("closeOrder", closeOrder)
|
||||
c.AddFunc("queryOrder", queryOrder)
|
||||
}
|
||||
|
||||
// 关闭长时间支付中的订单
|
||||
func closeOrder() {
|
||||
var now = time.Now().Format(time.DateTime)
|
||||
utils.Log(nil, "关闭订单", now)
|
||||
var ctx = context.Background()
|
||||
orderIds := make([]int64, 0)
|
||||
// 查询未支付的订单
|
||||
repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb())
|
||||
// 拼接条件
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"status": common.ORDER_STATUS_PAYING}, builder.Lt{"orders.create_time": time.Now().Add(-time.Second * time.Duration(config.GetConf().CronConfig.CloseOrderTime))})
|
||||
// 查询订单
|
||||
order := make([]ordersmodel.OrdersLeftPayChannelList, 0)
|
||||
err := repo.OrdersLeftPayChannelList(cond, entities.PageRequest{}, &order)
|
||||
if err != nil {
|
||||
utils.Log(nil, "关闭订单,查询未支付订单失败", err)
|
||||
} else if len(order) > 0 {
|
||||
for i := range order {
|
||||
orderInfo := order[i]
|
||||
// 往上游发送关闭订单请求
|
||||
req := paymentService.OrderCloseRequest{OrderId: orderInfo.Id}
|
||||
|
||||
switch utils.PayType(orderInfo.ChannelType) {
|
||||
case common.PAY_CHANNLE_TYPE_WECHAT:
|
||||
wx := backend.WechatPayChannel{}
|
||||
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &wx)
|
||||
req.PayChannel = payCommon.PAY_CHANNLE_TYPE_WECHAT
|
||||
req.Wx = paymentService.WxPay{
|
||||
AppId: orderInfo.AppId,
|
||||
MchId: wx.MchId,
|
||||
SerialNo: wx.SerialNo,
|
||||
ApiV3Key: wx.ApiV3Key,
|
||||
PrivateKey: wx.PrivateKey,
|
||||
}
|
||||
case common.PAY_CHANNLE_TYPE_ZFB:
|
||||
var ali backend.AliPayChannel
|
||||
|
||||
req.PayChannel = payCommon.PAY_CHANNLE_TYPE_ZFB
|
||||
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &ali)
|
||||
req.Ali = paymentService.AliPay{
|
||||
AppId: orderInfo.AppId,
|
||||
PrivateKey: ali.PrivateKey,
|
||||
AppPublicCert: ali.AppPublicCert,
|
||||
AlipayRootCert: ali.AlipayRootCert,
|
||||
AlipayPublicCert: ali.AlipayPublicCert,
|
||||
}
|
||||
default:
|
||||
utils.Log(nil, "关闭订单,支付渠道不支持", orderInfo.ChannelType)
|
||||
continue
|
||||
}
|
||||
// 发起关闭订单请求
|
||||
response := paymentService.OrderClose(ctx, req)
|
||||
// 成功
|
||||
if response.Code != payCommon.PAY_SUCCESS_CODE {
|
||||
utils.Log(nil, "关闭订单,上游失败", response, orderInfo.Id)
|
||||
}
|
||||
orderIds = append(orderIds, orderInfo.Id)
|
||||
// 回调通知下游
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, common.ORDER_STATUS_CLOSE, 0, "长时间未支付关闭订单")
|
||||
//utils.Log(nil, "主动查询订单支付状态,回调下游", notifyResult)
|
||||
if notifyResult.ErrCode != errorcode.Success {
|
||||
utils.Log(nil, "关闭订单,回调下游失败", fmt.Sprintf("%#v", notifyResult))
|
||||
}
|
||||
}
|
||||
// 修改订单状态为关闭
|
||||
cond = builder.NewCond()
|
||||
cond = cond.And(builder.In("id", orderIds))
|
||||
_, err = repo.OrderUpdate(&ordersmodel.Orders{Status: common.ORDER_STATUS_CLOSE}, cond, "status")
|
||||
if err != nil {
|
||||
utils.Log(nil, "关闭订单,修改订单状态失败", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
utils.Log(nil, "关闭订单,修改订单状态成功", "总数量="+strconv.Itoa(len(order)), "成功数量="+strconv.Itoa(len(orderIds)))
|
||||
}
|
||||
|
||||
// 主动查询订单支付状态
|
||||
func queryOrder() {
|
||||
var now = time.Now().Format(time.DateTime)
|
||||
utils.Log(nil, "主动查询订单支付状态", now)
|
||||
ctx := context.Background()
|
||||
// 查询未支付的订单
|
||||
repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb())
|
||||
// 拼接条件
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"status": common.ORDER_STATUS_PAYING}, builder.Gt{"orders.create_time": time.Now().Add(-time.Second * time.Duration(config.GetConf().CronConfig.QueryOrderTime))})
|
||||
cond = cond.And(builder.Eq{"order_type": common.ORDER_TYPE_PAY})
|
||||
order := make([]ordersmodel.OrdersLeftPayChannelList, 0)
|
||||
err := repo.OrdersLeftPayChannelList(cond, entities.PageRequest{}, &order)
|
||||
if err != nil {
|
||||
utils.Log(nil, "主动查询订单支付状态,查询未付中订单失败", err)
|
||||
return
|
||||
} else if len(order) > 0 {
|
||||
ch := make(chan struct{}, config.GetConf().CronConfig.ConcurrentNumber)
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
for index := range order {
|
||||
ch <- struct{}{}
|
||||
wg.Add(1)
|
||||
orderInfo := order[index]
|
||||
|
||||
// 发起查询上游支付
|
||||
go func(orderInfo ordersmodel.OrdersLeftPayChannelList) {
|
||||
defer func() {
|
||||
<-ch
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
query := paymentService.PayOrderQueryRequest{
|
||||
OrderId: orderInfo.Id,
|
||||
}
|
||||
switch utils.PayType(orderInfo.ChannelType) {
|
||||
case common.PAY_CHANNLE_TYPE_WECHAT:
|
||||
wx := backend.WechatPayChannel{}
|
||||
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &wx)
|
||||
query.PayChannel = payCommon.PAY_CHANNLE_TYPE_WECHAT
|
||||
query.Wx = paymentService.WxPay{
|
||||
AppId: orderInfo.AppId,
|
||||
MchId: wx.MchId,
|
||||
SerialNo: wx.SerialNo,
|
||||
ApiV3Key: wx.ApiV3Key,
|
||||
PrivateKey: wx.PrivateKey,
|
||||
}
|
||||
case common.PAY_CHANNLE_TYPE_ZFB:
|
||||
ali := backend.AliPayChannel{}
|
||||
query.PayChannel = payCommon.PAY_CHANNLE_TYPE_ZFB
|
||||
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &ali)
|
||||
query.Ali = paymentService.AliPay{
|
||||
AppId: orderInfo.AppId,
|
||||
PrivateKey: ali.PrivateKey,
|
||||
AppPublicCert: ali.AppPublicCert,
|
||||
AlipayRootCert: ali.AlipayRootCert,
|
||||
AlipayPublicCert: ali.AlipayPublicCert,
|
||||
}
|
||||
default:
|
||||
utils.Log(nil, "查询订单,支付渠道不支持", orderInfo.ChannelType)
|
||||
return
|
||||
}
|
||||
|
||||
// 发起查询
|
||||
result := paymentService.PayOrderQuery(ctx, query)
|
||||
utils.Log(nil, "主动查询订单支付状态,上游返回数据", result)
|
||||
// 查询成功,校验状态
|
||||
var status int
|
||||
if result.Code == payCommon.PAY_SUCCESS_CODE {
|
||||
var msg string
|
||||
switch result.Result.TradeState {
|
||||
case "SUCCESS":
|
||||
// 成功
|
||||
status = common.ORDER_STATUS_PAYED
|
||||
msg = "支付成功"
|
||||
case "REFUND":
|
||||
// 退款 订单支付完成才能退款,所以支付单的状态是支付完成
|
||||
status = common.ORDER_STATUS_PAYED
|
||||
msg = "支付成功"
|
||||
case "NOTPAY":
|
||||
// 未支付
|
||||
return
|
||||
case "CLOSED":
|
||||
// 关闭
|
||||
status = common.ORDER_STATUS_CLOSE
|
||||
msg = "订单关闭"
|
||||
}
|
||||
// 回调通知下游 todo
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, status, int(result.Result.PayerTotal), msg)
|
||||
//utils.Log(nil, "主动查询订单支付状态,回调下游", notifyResult)
|
||||
if notifyResult.ErrCode != errorcode.Success {
|
||||
utils.Log(nil, "主动查询订单支付状态,回调下游失败", fmt.Sprintf("%+v", notifyResult))
|
||||
}
|
||||
}
|
||||
}(orderInfo)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// 主动查询退款订单状态
|
||||
func queryRefundOrder() {
|
||||
var now = time.Now().Format(time.DateTime)
|
||||
utils.Log(nil, "主动查询退款订单状态", now)
|
||||
ctx := context.Background()
|
||||
// 查询退款中的订单
|
||||
repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb())
|
||||
// 拼接条件
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"status": common.ORDER_STATUS_PAYING}, builder.Gt{"orders.create_time": time.Now().Add(-time.Second * time.Duration(config.GetConf().CronConfig.QueryOrderTime))})
|
||||
cond = cond.And(builder.Eq{"order_type": common.ORDER_TYPE_REFUND})
|
||||
order := make([]ordersmodel.OrdersLeftPayChannelList, 0)
|
||||
err := repo.OrdersLeftPayChannelList(cond, entities.PageRequest{}, &order)
|
||||
if err != nil {
|
||||
utils.Log(nil, "主动查询退款订单状态,查询退款中订单失败", err)
|
||||
return
|
||||
} else if len(order) > 0 {
|
||||
ch := make(chan struct{}, config.GetConf().CronConfig.ConcurrentNumber)
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
for index := range order {
|
||||
ch <- struct{}{}
|
||||
wg.Add(1)
|
||||
orderInfo := order[index]
|
||||
|
||||
// 发起查询上游
|
||||
go func(orderInfo ordersmodel.OrdersLeftPayChannelList) {
|
||||
defer func() {
|
||||
<-ch
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
query := paymentService.OrderRefundQueryRequest{
|
||||
RefundOrderId: orderInfo.Id,
|
||||
OrderId: orderInfo.RefundOrderId,
|
||||
}
|
||||
switch utils.PayType(orderInfo.ChannelType) {
|
||||
case common.PAY_CHANNLE_TYPE_WECHAT:
|
||||
wx := backend.WechatPayChannel{}
|
||||
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &wx)
|
||||
query.PayChannel = payCommon.PAY_CHANNLE_TYPE_WECHAT
|
||||
query.Wx = paymentService.WxPay{
|
||||
AppId: orderInfo.AppId,
|
||||
MchId: wx.MchId,
|
||||
SerialNo: wx.SerialNo,
|
||||
ApiV3Key: wx.ApiV3Key,
|
||||
PrivateKey: wx.PrivateKey,
|
||||
}
|
||||
case common.PAY_CHANNLE_TYPE_ZFB:
|
||||
ali := backend.AliPayChannel{}
|
||||
query.PayChannel = payCommon.PAY_CHANNLE_TYPE_ZFB
|
||||
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &ali)
|
||||
query.Ali = paymentService.AliPay{
|
||||
AppId: orderInfo.AppId,
|
||||
PrivateKey: ali.PrivateKey,
|
||||
AppPublicCert: ali.AppPublicCert,
|
||||
AlipayRootCert: ali.AlipayRootCert,
|
||||
AlipayPublicCert: ali.AlipayPublicCert,
|
||||
}
|
||||
default:
|
||||
utils.Log(nil, "查询订单,支付渠道不支持", orderInfo.ChannelType)
|
||||
return
|
||||
}
|
||||
|
||||
// 发起查询
|
||||
result := paymentService.OrderRefundQuery(ctx, query)
|
||||
utils.Log(nil, "主动查询退款订单状态,上游返回数据", result)
|
||||
// 查询成功,校验状态
|
||||
var status int
|
||||
if result.Code == payCommon.PAY_SUCCESS_CODE {
|
||||
// 退款状态 0:未申请,1:退款中,2:退款成功,3:退款失败
|
||||
var msg string
|
||||
switch result.Result.RefundStatus {
|
||||
case 0:
|
||||
// 未申请
|
||||
utils.Log(nil, "主动查询退款订单状态,未申请", status)
|
||||
return
|
||||
case 1:
|
||||
// 退款中
|
||||
status = common.ORDER_STATUS_PAYING
|
||||
return
|
||||
case 2:
|
||||
// 退款成功
|
||||
status = common.ORDER_STATUS_PAYED
|
||||
msg = "退款成功"
|
||||
case 3:
|
||||
// 退款失败
|
||||
status = common.ORDER_STATUS_FAILED
|
||||
msg = "退款失败"
|
||||
}
|
||||
// 回调通知下游 todo
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, status, int(result.Result.RefundFee), msg)
|
||||
//utils.Log(nil, "主动查询退款订单状态,回调下游", notifyResult)
|
||||
if notifyResult.ErrCode != errorcode.Success {
|
||||
utils.Log(nil, "查询退款订单状态,回调下游失败", notifyResult)
|
||||
}
|
||||
}
|
||||
}(orderInfo)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// 回调下游
|
||||
func callbackOrder() {
|
||||
var now = time.Now().Format(time.DateTime)
|
||||
utils.Log(nil, "回调下游", now)
|
||||
// 查询回调失败的订单
|
||||
|
||||
// 发起回调
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package console
|
||||
|
||||
import (
|
||||
"PaymentCenter/config"
|
||||
"fmt"
|
||||
"github.com/robfig/cron"
|
||||
)
|
||||
|
||||
|
@ -9,7 +11,11 @@ import (
|
|||
* @wiki https://godoc.org/github.com/robfig/cron
|
||||
*/
|
||||
func RegisterSchedule(c *cron.Cron) {
|
||||
fmt.Println(config.GetConf().CronConfig)
|
||||
//c.AddFunc("0 30 * * * *", test)
|
||||
//c.AddFunc("@hourly", test)
|
||||
c.AddFunc("@every 10s", test)
|
||||
//c.AddFunc("@every 10s", test)
|
||||
c.AddFunc("@every 60s", closeOrder)
|
||||
c.AddFunc("@every 10s", queryOrder)
|
||||
c.AddFunc("@every 60s", queryRefundOrder)
|
||||
}
|
||||
|
|
|
@ -3,5 +3,73 @@ package common
|
|||
const (
|
||||
TOKEN_PRE = "player_token_"
|
||||
TOKEN_Admin = "Admin_token_"
|
||||
ADMIN_V1 = "/admin/api/v1"
|
||||
ADMIN_V1 = "/pay/admin/api/v1"
|
||||
FRONT_V1 = "/pay/front/api/v1"
|
||||
|
||||
// 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||
PAY_CHANNEL_UNKNOWN = 0
|
||||
PAY_CHANNEL_WECHAT_JSAPI = 1
|
||||
PAY_CHANNEL_WECHAT_H5 = 2
|
||||
PAY_CHANNEL_WECHAT_APP = 3
|
||||
PAY_CHANNEL_WECHAT_NATIVE = 4
|
||||
PAY_CHANNEL_WECHAT_MINI = 5
|
||||
PAY_CHANNEL_ALIPAY_WEB = 6
|
||||
PAY_CHANNEL_ALIPAY_MINI = 7
|
||||
PAY_CHANNEL_ALIPAY_JSAPI = 8
|
||||
|
||||
// 统一登陆信息
|
||||
ADMIN_USER_ID = "User-Id"
|
||||
ADMIN_USER_NAME = "User-Name"
|
||||
ADMIN_USER_INCLUDEUSERS = "Include-Users"
|
||||
|
||||
// '订单状态: 1待支付、2支付中、3支付成功、4支付失败、5订单关闭
|
||||
ORDER_STATUS_WAITPAY = 1
|
||||
ORDER_STATUS_PAYING = 2
|
||||
ORDER_STATUS_PAYED = 3
|
||||
ORDER_STATUS_FAILED = 4
|
||||
ORDER_STATUS_CLOSE = 5
|
||||
|
||||
// 订单类型,1支付,2退款
|
||||
ORDER_TYPE_PAY = 1
|
||||
ORDER_TYPE_REFUND = 2
|
||||
|
||||
STATUS_ENABLE = 1
|
||||
STATUS_DISABLED = 2
|
||||
|
||||
PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信
|
||||
PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝
|
||||
|
||||
THIRD_ORDER_TYPE_PAY = 1 // 发起支付
|
||||
THIRD_ORDER_TYPE_ORDER_QUERY = 2 // 查询订单
|
||||
THIRD_ORDER_TYPE_REFUND = 3 // 发起退款
|
||||
THIRD_ORDER_TYPE_REFUND_QUERY = 4 // 退款查询
|
||||
THIRD_ORDER_TYPE_CLOSE = 5 // 关闭订单
|
||||
THIRD_ORDER_TYPE_CALL_BACK = 6 // 支付回调
|
||||
|
||||
THIRD_ORDER_LOG_STATUS_COMMON = 0 // 第三方日志状态 未知
|
||||
THIRD_ORDER_LOG_STATUS_FAIL = 1 // 第三方日志状态 失败
|
||||
THIRD_ORDER_LOG_STATUS_SUCCESS = 2 // 第三方日志状态 成功
|
||||
)
|
||||
|
||||
var PayChannelList = map[int]string{
|
||||
PAY_CHANNEL_WECHAT_JSAPI: "微信JSAPI",
|
||||
PAY_CHANNEL_WECHAT_H5: "微信H5",
|
||||
PAY_CHANNEL_WECHAT_APP: "微信app",
|
||||
PAY_CHANNEL_WECHAT_NATIVE: "微信Native",
|
||||
PAY_CHANNEL_WECHAT_MINI: "微信小程序",
|
||||
PAY_CHANNEL_ALIPAY_WEB: "支付宝网页&移动应用",
|
||||
PAY_CHANNEL_ALIPAY_MINI: "支付宝小程序",
|
||||
PAY_CHANNEL_ALIPAY_JSAPI: "支付宝JSAPI",
|
||||
}
|
||||
|
||||
var OrderTypeList = map[int]string{
|
||||
ORDER_TYPE_PAY: "付款",
|
||||
ORDER_TYPE_REFUND: "退款",
|
||||
}
|
||||
var OrderStatusMap = map[int]string{
|
||||
ORDER_STATUS_WAITPAY: "等待执行",
|
||||
ORDER_STATUS_PAYING: "执行中",
|
||||
ORDER_STATUS_PAYED: "执行成功",
|
||||
ORDER_STATUS_FAILED: "执行失败",
|
||||
ORDER_STATUS_CLOSE: "订单关闭",
|
||||
}
|
||||
|
|
|
@ -19,8 +19,67 @@ const (
|
|||
//系统错误
|
||||
SystemError = 500
|
||||
|
||||
//请求超时
|
||||
RequestTimeOut = 600
|
||||
|
||||
//未登录
|
||||
NotLogin = 1000
|
||||
|
||||
// 商户
|
||||
MerchantNotFound = 1100
|
||||
|
||||
// app
|
||||
|
||||
AppNotFound = 1200
|
||||
AppDisabled = 1201
|
||||
AppIpNotAllow = 1202
|
||||
AppRsaDecryptKeyNotFound = 1203
|
||||
AppDecryptDataDiscrepancy = 1204
|
||||
AppNotifyUrlNotFound = 1205
|
||||
AppRsaDecryptFail = 1210
|
||||
AppRsaEncryptKeyNotFound = 1211
|
||||
AppRsaEncryptFail = 1212
|
||||
AppSM2DecryptKeyNotFound = 1220
|
||||
AppSM2DecryptFail = 1221
|
||||
AppSM2EncryptKeyNotFound = 1222
|
||||
AppSM2EncryptFail = 1223
|
||||
AppSM4DecryptKeyNotFound = 1230
|
||||
AppSM4DecryptFail = 1231
|
||||
AppSM4EncryptKeyNotFound = 1232
|
||||
AppSM4EncryptFail = 1233
|
||||
AppAesEncryptFail = 1234
|
||||
AppDeEncryptFail = 1250
|
||||
// 加密方式不存在
|
||||
EncryptTypeNotFound = 1241
|
||||
|
||||
//渠道
|
||||
PayChannelNotFound = 1300
|
||||
PayChannelNotBuild = 1301
|
||||
PayChannelExtJsonError = 1302
|
||||
|
||||
//订单
|
||||
OrdersNotFound = 1401
|
||||
OrdersExist = 1402
|
||||
OrderTypeNotFount = 1403
|
||||
OrderIsDelete = 1405
|
||||
OrderStatusErr = 1406
|
||||
OrderClosed = 1407
|
||||
OrderFailed = 1408
|
||||
OrderPayed = 1409
|
||||
RefundOrderNotFound = 1410
|
||||
OrderStatusRefundNotSupport = 1411
|
||||
|
||||
//请求日志
|
||||
RequestLogErrors = 1500
|
||||
RequestLogNotFound = 1501
|
||||
RequestResponseValid = 1502
|
||||
|
||||
//回调
|
||||
NotifySendFail = 1600
|
||||
|
||||
//订单结果
|
||||
PrePayFail = 1701
|
||||
PreRefundFail = 1702
|
||||
)
|
||||
|
||||
var MsgEN = map[int]string{
|
||||
|
@ -33,11 +92,61 @@ var MsgEN = map[int]string{
|
|||
}
|
||||
|
||||
var MsgZH = map[int]string{
|
||||
Success: "请求成功",
|
||||
ParamError: "参数错误",
|
||||
NotFound: "数据不存在",
|
||||
NotAuth: "未经授权",
|
||||
NotLogin: "未登录",
|
||||
Success: "请求成功",
|
||||
ParamError: "参数错误",
|
||||
NotFound: "数据不存在",
|
||||
NotAuth: "未经授权",
|
||||
NotLogin: "未登录",
|
||||
RequestTimeOut: "请求超时",
|
||||
MerchantNotFound: "商户不存在",
|
||||
AppNotFound: "app_id未找到",
|
||||
AppDisabled: "app通道关闭",
|
||||
AppIpNotAllow: "ip不在白名单内",
|
||||
AppDecryptDataDiscrepancy: "解密数据不一致",
|
||||
SystemError: "系统错误",
|
||||
AppNotifyUrlNotFound: "未设置回调地址",
|
||||
|
||||
AppRsaDecryptKeyNotFound: "密匙缺失,无法进行Rsa解密",
|
||||
AppRsaDecryptFail: "Rsa解密失败",
|
||||
AppRsaEncryptKeyNotFound: "密匙缺失,无法进行Rsa加密",
|
||||
AppRsaEncryptFail: "Rsa加密失败",
|
||||
|
||||
AppSM2DecryptKeyNotFound: "密匙缺失,无法进行sm2解密",
|
||||
AppSM2DecryptFail: "sm2解密失败",
|
||||
AppSM2EncryptKeyNotFound: "密匙缺失,无法进行sm2加密",
|
||||
AppSM2EncryptFail: "sm2加密失败",
|
||||
|
||||
AppSM4DecryptKeyNotFound: "密匙缺失,无法进行sm4解密",
|
||||
AppSM4DecryptFail: "sm4解密失败",
|
||||
AppSM4EncryptKeyNotFound: "密匙缺失,无法进行sm4加密",
|
||||
AppSM4EncryptFail: "sm4加密失败",
|
||||
|
||||
AppAesEncryptFail: "aes 加密失败",
|
||||
|
||||
EncryptTypeNotFound: "加密方式不存在",
|
||||
|
||||
AppDeEncryptFail: "未知原因导致解密失败,请检查加密数据是和app加密配置",
|
||||
|
||||
PayChannelNotFound: "支付方式不存在",
|
||||
PayChannelNotBuild: "支付方式尚未开通",
|
||||
PayChannelExtJsonError: "支付方式扩展参数错误",
|
||||
|
||||
RequestLogErrors: "请求日志错误",
|
||||
RequestLogNotFound: "未找到日志信息",
|
||||
RequestResponseValid: "上游返回格式无效",
|
||||
|
||||
OrdersNotFound: "未找到订单",
|
||||
OrdersExist: "订单已存在",
|
||||
OrderTypeNotFount: "未知的支付方式",
|
||||
OrderIsDelete: "订单已删除",
|
||||
OrderStatusErr: "订单状态错误",
|
||||
OrderClosed: "订单已关闭,无法继续支付",
|
||||
OrderFailed: "订单支付失败,请重新发起",
|
||||
OrderPayed: "订单已支付成功,请勿重复支付",
|
||||
NotifySendFail: "回调发送失败",
|
||||
RefundOrderNotFound: "退款订单未找到",
|
||||
OrderStatusRefundNotSupport: "订单状态不支持退款",
|
||||
PrePayFail: "预支付失败",
|
||||
}
|
||||
var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package pojo
|
||||
|
||||
const (
|
||||
RSA int32 = iota + 1
|
||||
SM2
|
||||
SM4
|
||||
)
|
|
@ -0,0 +1,48 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"database/sql"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type AppRepo struct {
|
||||
repo xorm.Interface
|
||||
}
|
||||
|
||||
func NewAppRepo(repo xorm.Interface) *AppRepo {
|
||||
return &AppRepo{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AppRepo) AppList(conn builder.Cond, pageFilter entities.PageRequest, appList *[]appmodel.App) (int64, error) {
|
||||
repo := m.repo.Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
return repo.Desc("create_time").FindAndCount(appList)
|
||||
}
|
||||
|
||||
func (m *AppRepo) AppInsertOne(app *appmodel.App) (int64, error) {
|
||||
return m.repo.InsertOne(app)
|
||||
}
|
||||
|
||||
func (m *AppRepo) AppDelete(app *appmodel.App, conn builder.Cond) (int64, error) {
|
||||
return m.repo.Where(conn).Delete(app)
|
||||
}
|
||||
|
||||
// columns 参数为要更新的字段
|
||||
func (m *AppRepo) AppUpdate(app *appmodel.App, conn builder.Cond, columns ...string) (int64, error) {
|
||||
return m.repo.Where(conn).MustCols(columns...).Update(app)
|
||||
}
|
||||
|
||||
func (m *AppRepo) AppFindOne(app *appmodel.App, conn builder.Cond, columns ...string) (*appmodel.App, error) {
|
||||
has, err := m.repo.Where(conn).Get(app)
|
||||
if !has {
|
||||
return nil, sql.ErrNoRows
|
||||
}
|
||||
return app, err
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package data
|
|
@ -0,0 +1,52 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
"database/sql"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type MerchantRepo struct {
|
||||
repo xorm.Interface
|
||||
}
|
||||
|
||||
func NewMerchantRepo(repo xorm.Interface) *MerchantRepo {
|
||||
return &MerchantRepo{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MerchantRepo) MerchantList(conn builder.Cond, pageFilter entities.PageRequest, merchantList *[]merchantmodel.Merchant) (int64, error) {
|
||||
repo := m.repo.Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
return repo.Desc("create_time").FindAndCount(merchantList)
|
||||
}
|
||||
|
||||
func (m *MerchantRepo) MerchantInsertOne(merchant *merchantmodel.Merchant) (int64, error) {
|
||||
return m.repo.InsertOne(merchant)
|
||||
}
|
||||
|
||||
func (m *MerchantRepo) MerchantDelete(merchant *merchantmodel.Merchant, conn builder.Cond) (int64, error) {
|
||||
return m.repo.Where(conn).Delete(merchant)
|
||||
}
|
||||
|
||||
// columns 参数为要更新的字段
|
||||
func (m *MerchantRepo) MerchantUpdate(merchant *merchantmodel.Merchant, conn builder.Cond, columns ...string) (int64, error) {
|
||||
return m.repo.Where(conn).MustCols(columns...).Update(merchant)
|
||||
}
|
||||
|
||||
func (m *MerchantRepo) MerchantDetail(merchant *merchantmodel.Merchant, conn builder.Cond) (bool, error) {
|
||||
return m.repo.Where(conn).Get(merchant)
|
||||
}
|
||||
|
||||
func (m *MerchantRepo) MerchantFindOne(merchant *merchantmodel.Merchant, conn builder.Cond, columns ...string) (*merchantmodel.Merchant, error) {
|
||||
has, err := m.repo.Where(conn).Get(merchant)
|
||||
if !has {
|
||||
return nil, sql.ErrNoRows
|
||||
}
|
||||
return merchant, err
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/ordercallbacklogmodel"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type OrderCallbackLogRepo struct {
|
||||
repo xorm.Interface
|
||||
}
|
||||
|
||||
func NewOrderCallbackLogRepo(repo xorm.Interface) *OrderCallbackLogRepo {
|
||||
return &OrderCallbackLogRepo{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *OrderCallbackLogRepo) OrderCallbackLogList(conn builder.Cond, pageFilter entities.PageRequest, orderLogList *[]ordercallbacklogmodel.OrderCallbackLog) (int64, error) {
|
||||
repo := m.repo.Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
return repo.Desc("create_time").FindAndCount(orderLogList)
|
||||
}
|
||||
|
||||
func (m *OrderCallbackLogRepo) OrderCallbackLogInsertOne(orderLog *ordercallbacklogmodel.OrderCallbackLog) (int64, error) {
|
||||
return m.repo.InsertOne(orderLog)
|
||||
}
|
||||
|
||||
func (m *OrderCallbackLogRepo) OrderCallbackLogDelete(orderLog *ordercallbacklogmodel.OrderCallbackLog, conn builder.Cond) (int64, error) {
|
||||
return m.repo.Where(conn).Delete(orderLog)
|
||||
}
|
||||
|
||||
// columns 参数为要更新的字段
|
||||
func (m *OrderCallbackLogRepo) OrderCallbackLogUpdate(orderLog *ordercallbacklogmodel.OrderCallbackLog, conn builder.Cond, columns ...string) (int64, error) {
|
||||
return m.repo.Where(conn).MustCols(columns...).Update(orderLog)
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/orderrequestlogmodel"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type OrderRequestLogRepo struct {
|
||||
repo xorm.Interface
|
||||
}
|
||||
|
||||
func NewOrderRequestLogRepo(repo xorm.Interface) *OrderRequestLogRepo {
|
||||
return &OrderRequestLogRepo{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *OrderRequestLogRepo) OrderRequestLogList(conn builder.Cond, pageFilter entities.PageRequest, orderLogList *[]orderrequestlogmodel.OrderRequestLog) (int64, error) {
|
||||
repo := m.repo.Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
return repo.Desc("create_time").FindAndCount(orderLogList)
|
||||
}
|
||||
|
||||
func (m *OrderRequestLogRepo) OrderRequestLogInsertOne(orderLog *orderrequestlogmodel.OrderRequestLog) (int64, error) {
|
||||
return m.repo.InsertOne(orderLog)
|
||||
}
|
||||
|
||||
func (m *OrderRequestLogRepo) OrderRequestLogDelete(orderLog *orderrequestlogmodel.OrderRequestLog, conn builder.Cond) (int64, error) {
|
||||
return m.repo.Where(conn).Delete(orderLog)
|
||||
}
|
||||
|
||||
// columns 参数为要更新的字段
|
||||
func (m *OrderRequestLogRepo) OrderRequestLogUpdate(orderLog *orderrequestlogmodel.OrderRequestLog, conn builder.Cond, columns ...string) (int64, error) {
|
||||
return m.repo.Where(conn).MustCols(columns...).Update(orderLog)
|
||||
}
|
||||
|
||||
// 后台查询订单日志列表
|
||||
func (m *OrderRequestLogRepo) OrderRequestLogBackendList(conn builder.Cond, pageFilter entities.PageRequest, orderLogList *[]orderrequestlogmodel.OrderRequestLog) (int64, error) {
|
||||
repo := m.repo.Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
repo.Join("left", "orders", "orders.app_id = order_request_log.app_id and orders.out_trade_no = order_request_log.out_trade_no")
|
||||
return repo.Desc("order_request_log.create_time").FindAndCount(orderLogList)
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/orderthirdpaylogmodel"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type OrderThirdPayLogRepo struct {
|
||||
repo xorm.Interface
|
||||
}
|
||||
|
||||
func NewOrderThirdPayLogRepo(repo xorm.Interface) *OrderThirdPayLogRepo {
|
||||
return &OrderThirdPayLogRepo{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *OrderThirdPayLogRepo) OrderThirdPayLogList(conn builder.Cond, pageFilter entities.PageRequest, orderLogList *[]orderthirdpaylogmodel.OrderThirdPayLog) (int64, error) {
|
||||
repo := m.repo.Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
return repo.Desc("create_time").FindAndCount(orderLogList)
|
||||
}
|
||||
|
||||
func (m *OrderThirdPayLogRepo) OrderThirdPayLogInsertOne(orderLog *orderthirdpaylogmodel.OrderThirdPayLog) (int64, error) {
|
||||
return m.repo.InsertOne(orderLog)
|
||||
}
|
||||
|
||||
func (m *OrderThirdPayLogRepo) OrderThirdPayLogDelete(orderLog *orderthirdpaylogmodel.OrderThirdPayLog, conn builder.Cond) (int64, error) {
|
||||
return m.repo.Where(conn).Delete(orderLog)
|
||||
}
|
||||
|
||||
// columns 参数为要更新的字段
|
||||
func (m *OrderThirdPayLogRepo) OrderThirdPayLogUpdate(orderLog *orderthirdpaylogmodel.OrderThirdPayLog, conn builder.Cond, columns ...string) (int64, error) {
|
||||
return m.repo.Where(conn).MustCols(columns...).Update(orderLog)
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"database/sql"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type OrderRepo struct {
|
||||
repo xorm.Interface
|
||||
}
|
||||
|
||||
func NewOrderRepo(repo xorm.Interface) *OrderRepo {
|
||||
return &OrderRepo{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *OrderRepo) OrderList(conn builder.Cond, pageFilter entities.PageRequest, orderList *[]ordersmodel.Orders) (int64, error) {
|
||||
repo := m.repo.Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
return repo.Desc("create_time").FindAndCount(orderList)
|
||||
}
|
||||
|
||||
func (m *OrderRepo) OrderInsertOne(order *ordersmodel.Orders) (int64, error) {
|
||||
return m.repo.InsertOne(order)
|
||||
}
|
||||
|
||||
func (m *OrderRepo) OrderDelete(order *ordersmodel.Orders, conn builder.Cond) (int64, error) {
|
||||
return m.repo.Where(conn).Delete(order)
|
||||
}
|
||||
|
||||
// columns 参数为要更新的字段
|
||||
func (m *OrderRepo) OrderUpdate(order *ordersmodel.Orders, conn builder.Cond, columns ...string) (int64, error) {
|
||||
return m.repo.Where(conn).MustCols(columns...).Update(order)
|
||||
}
|
||||
|
||||
func (m *OrderRepo) OrdersBackendList(conn builder.Cond, pageFilter entities.PageRequest, orderList *[]ordersmodel.OrdersBackendList) (int64, error) {
|
||||
repo := m.repo.Select(`orders.*, merchant.name as merchant_name, app.app_name, pay_channel.pay_name`).
|
||||
Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
repo = repo.Join("left", "app", "app.id = orders.app_id").
|
||||
Join("left", "merchant", "merchant.id = orders.merchant_id").
|
||||
Join("left", "pay_channel", "pay_channel.id = orders.pay_channel_id")
|
||||
return repo.Desc("orders.create_time").FindAndCount(orderList)
|
||||
}
|
||||
|
||||
func (m *OrderRepo) OrdersLeftPayChannelList(conn builder.Cond, pageFilter entities.PageRequest, orderList *[]ordersmodel.OrdersLeftPayChannelList) error {
|
||||
repo := m.repo.Select(`orders.*,pay_channel.channel_type,pay_channel.app_id ,pay_channel.ext_json`).
|
||||
Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
repo = repo.Join("left", "pay_channel", "pay_channel.id = orders.pay_channel_id")
|
||||
return repo.Find(orderList)
|
||||
}
|
||||
|
||||
func (m *OrderRepo) OrderFindOne(order *ordersmodel.Orders, conn builder.Cond, columns ...string) (*ordersmodel.Orders, error) {
|
||||
has, err := m.repo.Where(conn).Get(order)
|
||||
if !has {
|
||||
return nil, sql.ErrNoRows
|
||||
}
|
||||
return order, err
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"database/sql"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type PayChannelRepo struct {
|
||||
repo xorm.Interface
|
||||
}
|
||||
|
||||
func NewPayChannelRepo(repo xorm.Interface) *PayChannelRepo {
|
||||
return &PayChannelRepo{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *PayChannelRepo) PayChannelList(conn builder.Cond, pageFilter entities.PageRequest, payChannelList *[]paychannelmodel.PayChannel) (int64, error) {
|
||||
repo := m.repo.Where(conn)
|
||||
if pageFilter.Page > 0 {
|
||||
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
|
||||
}
|
||||
return repo.Desc("create_time").FindAndCount(payChannelList)
|
||||
}
|
||||
|
||||
func (m *PayChannelRepo) PayChannelInsertOne(payChannel *paychannelmodel.PayChannel) (int64, error) {
|
||||
return m.repo.InsertOne(payChannel)
|
||||
}
|
||||
|
||||
func (m *PayChannelRepo) PayChannelDelete(payChannel *paychannelmodel.PayChannel, conn builder.Cond) (int64, error) {
|
||||
return m.repo.Where(conn).Delete(payChannel)
|
||||
}
|
||||
|
||||
// columns 参数为要更新的字段,即使为空
|
||||
func (m *PayChannelRepo) PayChannelUpdate(payChannel *paychannelmodel.PayChannel, conn builder.Cond, columns ...string) (int64, error) {
|
||||
return m.repo.Where(conn).MustCols(columns...).Update(payChannel)
|
||||
}
|
||||
|
||||
func (m *PayChannelRepo) PayChannelGet(payChannel *paychannelmodel.PayChannel, conn builder.Cond) (bool, error) {
|
||||
return m.repo.Where(conn).Get(payChannel)
|
||||
}
|
||||
|
||||
func (m *PayChannelRepo) PayChannelFindOne(payChannel *paychannelmodel.PayChannel, conn builder.Cond, columns ...string) (*paychannelmodel.PayChannel, error) {
|
||||
has, err := m.repo.Where(conn).Get(payChannel)
|
||||
if !has {
|
||||
return nil, sql.ErrNoRows
|
||||
}
|
||||
return payChannel, err
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
"PaymentCenter/app/models/orderrequestlogmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay/api"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/config"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ApiRes(c *gin.Context, data interface{}, code int, msg ...string) {
|
||||
var logId int64
|
||||
var responseData interface{}
|
||||
var message string
|
||||
var appCheckInfo *services.AppCheck
|
||||
originData := "{}"
|
||||
appInfo := GetAppCheckInfo(c)
|
||||
if appInfo != nil {
|
||||
appCheckInfo = appInfo.(*services.AppCheck)
|
||||
}
|
||||
// 空数据
|
||||
if utils.IsNil(data) {
|
||||
data = struct{}{}
|
||||
}
|
||||
// 获取错误信息
|
||||
if len(msg) > 0 {
|
||||
message = msg[0]
|
||||
} else {
|
||||
message = errorcode.GetMsg(code, "")
|
||||
}
|
||||
// 获取日志ID
|
||||
log, exists := GetApiLogId(c)
|
||||
if exists {
|
||||
logId = log.(int64)
|
||||
}
|
||||
// 加密数据
|
||||
if code == errorcode.Success {
|
||||
if apiRsp, ok := data.(front.ApiResponse); ok {
|
||||
apiRsp.Order, code = api.EnCrypt(appCheckInfo.App, apiRsp.Order)
|
||||
if code != errorcode.Success {
|
||||
message = errorcode.GetMsg(code, "")
|
||||
}
|
||||
responseData = apiRsp
|
||||
} else {
|
||||
responseData = data
|
||||
}
|
||||
}
|
||||
|
||||
if code == errorcode.Success {
|
||||
ApiSuccess(c, responseData, logId, message)
|
||||
b, _ := json.Marshal(data)
|
||||
originData = string(b)
|
||||
} else {
|
||||
ApiError(c, code, logId, message)
|
||||
originData = fmt.Sprintf("{\"code\":%d,\"message\":\"%s\"}", code, message)
|
||||
}
|
||||
// 记录日志
|
||||
if logId > 0 {
|
||||
services.RequestLogUpdate(&orderrequestlogmodel.OrderRequestLog{
|
||||
Id: logId,
|
||||
AppId: appCheckInfo.AppId,
|
||||
OutTradeNo: GetOutTradeNo(c),
|
||||
MerchantResponse: originData,
|
||||
Status: common.STATUS_DISABLED,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func ApiSuccess(c *gin.Context, data interface{}, log_id int64, messageSlice ...string) {
|
||||
var message string
|
||||
if len(messageSlice) > 0 {
|
||||
message = messageSlice[0]
|
||||
}
|
||||
if message == "" {
|
||||
message = errorcode.GetMsg(errorcode.Success, c.GetHeader("local"))
|
||||
}
|
||||
if config.GetConf().Env == "production" {
|
||||
c.String(http.StatusOK, EncriptJson(gin.H{
|
||||
"code": errorcode.Success,
|
||||
"message": message,
|
||||
"data": data,
|
||||
"trace_id": log_id,
|
||||
}))
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": errorcode.Success,
|
||||
"message": message,
|
||||
"data": data,
|
||||
"trace_id": log_id,
|
||||
})
|
||||
}
|
||||
|
||||
c.Abort()
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败时返回
|
||||
*/
|
||||
func ApiError(c *gin.Context, code int, log_id int64, msg ...string) {
|
||||
message := ""
|
||||
if len(msg) > 0 {
|
||||
message = msg[0]
|
||||
} else {
|
||||
message = errorcode.GetMsg(code, "")
|
||||
}
|
||||
if config.GetConf().Env == "production" {
|
||||
c.String(http.StatusOK, EncriptJson(gin.H{
|
||||
"code": code,
|
||||
"message": message,
|
||||
"data": make(map[string]string),
|
||||
"trace_id": log_id,
|
||||
}))
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": code,
|
||||
"message": message,
|
||||
"data": make(map[string]string),
|
||||
"trace_id": log_id,
|
||||
})
|
||||
}
|
||||
|
||||
c.Abort()
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/constants/pojo"
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/utils/encrypt/rsa"
|
||||
"PaymentCenter/app/utils/encrypt/sm2"
|
||||
"PaymentCenter/app/utils/encrypt/sm4"
|
||||
"github.com/ahmetb/go-linq/v3"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func AppList(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.AppListRequest)
|
||||
req.SetDefault()
|
||||
payChannelList, total, code := services.AppList(*req)
|
||||
|
||||
result := make([]backend.AppResponse, 0, len(payChannelList))
|
||||
linq.From(payChannelList).SelectT(func(in appmodel.App) (out backend.AppResponse) {
|
||||
out.ResponseFromDb(in)
|
||||
return
|
||||
}).ToSlice(&result)
|
||||
data := entities.PageRsp{
|
||||
Total: total,
|
||||
Data: result,
|
||||
}
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func AppCreate(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.AppCreateRequest)
|
||||
payChannel, err := req.RequestToDb()
|
||||
if err != nil {
|
||||
controllers.Error(c, errorcode.ParamError, err.Error())
|
||||
return
|
||||
}
|
||||
code := services.AppCreate(&payChannel)
|
||||
|
||||
data := backend.AppResponse{}
|
||||
data.ResponseFromDb(payChannel)
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func AppUpdate(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.AppUpdateRequest)
|
||||
payChannel, err := req.RequestToDb()
|
||||
if err != nil {
|
||||
controllers.Error(c, errorcode.ParamError, err.Error())
|
||||
return
|
||||
}
|
||||
code := services.AppUpdate(&payChannel)
|
||||
|
||||
data := backend.AppResponse{}
|
||||
data.ResponseFromDb(payChannel)
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func AppDelete(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*entities.IdRequest)
|
||||
code := services.AppDelete(*req)
|
||||
controllers.HandCodeRes(c, nil, code)
|
||||
}
|
||||
|
||||
func GenerateDecrypt(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.GenerateDecryptKeyRequest)
|
||||
var publicKey, privateKey string
|
||||
var err error
|
||||
switch req.KeyType {
|
||||
case pojo.SM2:
|
||||
publicKey, privateKey, err = sm2.GenerateSM2Key()
|
||||
case pojo.RSA:
|
||||
publicKey, privateKey, err = rsa.GenerateKey()
|
||||
case pojo.SM4:
|
||||
privateKey, publicKey = sm4.GenerateKey()
|
||||
default:
|
||||
controllers.HandCodeRes(c, "", errorcode.EncryptTypeNotFound)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
controllers.Error(c, errorcode.SystemError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
controllers.HandCodeRes(c, map[string]string{
|
||||
"publicKey": publicKey,
|
||||
"privateKey": privateKey,
|
||||
}, errorcode.Success)
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"github.com/ahmetb/go-linq/v3"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func MerchantList(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.MerchantListRequest)
|
||||
req.SetDefault()
|
||||
req.GroupInfo = controllers.GetAdminUserIncludeUsers(c)
|
||||
merchantList, total, code := services.MerchantList(*req)
|
||||
|
||||
result := make([]backend.MerchantResponse, 0, len(merchantList))
|
||||
linq.From(merchantList).SelectT(func(in merchantmodel.Merchant) (out backend.MerchantResponse) {
|
||||
out.ResponseFromDb(in)
|
||||
return
|
||||
}).ToSlice(&result)
|
||||
data := entities.PageRsp{
|
||||
Total: total,
|
||||
Data: result,
|
||||
}
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func MerchantCreate(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.MerchantCreateRequest)
|
||||
merchant := req.RequestToDb()
|
||||
code := services.MerchantCreate(&merchant)
|
||||
|
||||
data := backend.MerchantResponse{}
|
||||
data.ResponseFromDb(merchant)
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func MerchantUpdate(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.MerchantUpdateRequest)
|
||||
merchant := req.RequestToDb()
|
||||
code := services.MerchantUpdate(&merchant)
|
||||
|
||||
data := backend.MerchantResponse{}
|
||||
data.ResponseFromDb(merchant)
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func MerchantDelete(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*entities.IdRequest)
|
||||
code := services.MerchantDelete(*req)
|
||||
controllers.HandCodeRes(c, nil, code)
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/ordercallbacklogmodel"
|
||||
"PaymentCenter/app/models/orderrequestlogmodel"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/models/orderthirdpaylogmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"github.com/ahmetb/go-linq/v3"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func OrderList(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.OrderListRequest)
|
||||
filter, err := req.ValidateRequest()
|
||||
if err != nil {
|
||||
controllers.Error(c, errorcode.ParamError, err.Error())
|
||||
return
|
||||
}
|
||||
orderList, total, code := services.OrderList(filter)
|
||||
|
||||
result := make([]backend.OrdersResponse, 0, len(orderList))
|
||||
linq.From(orderList).SelectT(func(in ordersmodel.OrdersBackendList) (out backend.OrdersResponse) {
|
||||
out.ResponseFromDb(in)
|
||||
return
|
||||
}).ToSlice(&result)
|
||||
data := entities.PageRsp{
|
||||
Total: total,
|
||||
Data: result,
|
||||
}
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func OrderRequestLogsList(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.OrderLogsListRequest)
|
||||
req.SetDefault()
|
||||
requestLog, total, code := services.OrderRequestLogsList(*req)
|
||||
|
||||
requestLogList := make([]backend.OrderRequestLogResponse, 0, len(requestLog))
|
||||
linq.From(requestLog).SelectT(func(in orderrequestlogmodel.OrderRequestLog) (out backend.OrderRequestLogResponse) {
|
||||
out.ResponseFromDb(in)
|
||||
return
|
||||
}).ToSlice(&requestLogList)
|
||||
|
||||
controllers.HandCodeRes(c, entities.PageRsp{
|
||||
Total: total,
|
||||
Data: requestLogList,
|
||||
}, code)
|
||||
}
|
||||
|
||||
func OrderThirdLogsList(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.OrderLogsListRequest)
|
||||
req.SetDefault()
|
||||
thirdLog, total, code := services.OrderThirdLogsList(*req)
|
||||
|
||||
thirdLogList := make([]backend.OrderThirdLogResponse, 0, len(thirdLog))
|
||||
linq.From(thirdLog).SelectT(func(in orderthirdpaylogmodel.OrderThirdPayLog) (out backend.OrderThirdLogResponse) {
|
||||
out.ResponseFromDb(in)
|
||||
return
|
||||
}).ToSlice(&thirdLogList)
|
||||
|
||||
controllers.HandCodeRes(c, entities.PageRsp{
|
||||
Total: total,
|
||||
Data: thirdLogList,
|
||||
}, code)
|
||||
}
|
||||
|
||||
func OrderCallbackLogsList(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.OrderLogsListRequest)
|
||||
req.SetDefault()
|
||||
callbackLog, total, code := services.OrderCallbackLogsList(*req)
|
||||
|
||||
callbackLogList := make([]backend.OrderCallbackLogResponse, 0, len(callbackLog))
|
||||
linq.From(callbackLog).SelectT(func(in ordercallbacklogmodel.OrderCallbackLog) (out backend.OrderCallbackLogResponse) {
|
||||
out.ResponseFromDb(in)
|
||||
return
|
||||
}).ToSlice(&callbackLogList)
|
||||
|
||||
controllers.HandCodeRes(c, entities.PageRsp{
|
||||
Total: total,
|
||||
Data: callbackLogList,
|
||||
}, code)
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"github.com/ahmetb/go-linq/v3"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func PayChannelList(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.PayChannelListRequest)
|
||||
req.SetDefault()
|
||||
payChannelList, total, code := services.PayChannelList(*req)
|
||||
|
||||
result := make([]backend.PayChannelResponse, 0, len(payChannelList))
|
||||
linq.From(payChannelList).SelectT(func(in paychannelmodel.PayChannel) (out backend.PayChannelResponse) {
|
||||
out.ResponseFromDb(in)
|
||||
return
|
||||
}).ToSlice(&result)
|
||||
data := entities.PageRsp{
|
||||
Total: total,
|
||||
Data: result,
|
||||
}
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func PayChannelCreate(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.PayChannelCreateRequest)
|
||||
payChannel, err := req.RequestToDb()
|
||||
if err != nil {
|
||||
controllers.Error(c, errorcode.ParamError, err.Error())
|
||||
return
|
||||
}
|
||||
code := services.PayChannelCreate(&payChannel)
|
||||
|
||||
data := backend.PayChannelResponse{}
|
||||
data.ResponseFromDb(payChannel)
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func PayChannelUpdate(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*backend.PayChannelUpdateRequest)
|
||||
payChannel, err := req.RequestToDb()
|
||||
if err != nil {
|
||||
controllers.Error(c, errorcode.ParamError, err.Error())
|
||||
return
|
||||
}
|
||||
code := services.PayChannelUpdate(&payChannel)
|
||||
|
||||
data := backend.PayChannelResponse{}
|
||||
data.ResponseFromDb(payChannel)
|
||||
controllers.HandCodeRes(c, data, code)
|
||||
}
|
||||
|
||||
func PayChannelDelete(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*entities.IdRequest)
|
||||
code := services.PayChannelDelete(*req)
|
||||
controllers.HandCodeRes(c, nil, code)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/config"
|
||||
"bytes"
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/go-playground/locales/zh"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/qit-team/snow-core/redis"
|
||||
|
@ -15,6 +17,9 @@ import (
|
|||
zh_translations "gopkg.in/go-playground/validator.v9/translations/zh"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
|
||||
|
@ -24,7 +29,11 @@ import (
|
|||
/**
|
||||
* 成功时返回
|
||||
*/
|
||||
func Success(c *gin.Context, data interface{}, message string) {
|
||||
func Success(c *gin.Context, data interface{}, messageSlice ...string) {
|
||||
var message string
|
||||
if len(messageSlice) > 0 {
|
||||
message = messageSlice[0]
|
||||
}
|
||||
if message == "" {
|
||||
message = errorcode.GetMsg(errorcode.Success, c.GetHeader("local"))
|
||||
}
|
||||
|
@ -103,17 +112,33 @@ func GenRequest(c *gin.Context, request interface{}) (msgs []string, err error)
|
|||
if c.Request.Method == "GET" || c.Request.Method == "DELETE" {
|
||||
err = c.ShouldBindQuery(request)
|
||||
} else {
|
||||
err = c.ShouldBindJSON(request)
|
||||
err = c.ShouldBind(request)
|
||||
}
|
||||
var req, _ = sonic.Marshal(request)
|
||||
utils.Log(c, c.FullPath(), "请求参数", string(req))
|
||||
|
||||
if err == nil {
|
||||
validate := validator.New()
|
||||
_ = validate.RegisterValidation("phoneValidation", phoneValidation)
|
||||
zh_ch := zh.New()
|
||||
|
||||
uni := ut.New(zh_ch)
|
||||
trans, _ := uni.GetTranslator("zh")
|
||||
_ = validate.RegisterTranslation("phoneValidation", trans, func(ut ut.Translator) error {
|
||||
return ut.Add("phoneValidation", "手机号不合法", true) // 添加翻译
|
||||
}, func(ut ut.Translator, fe validator.FieldError) string {
|
||||
t, _ := ut.T("phoneValidation", fe.Field()) // 获取翻译
|
||||
return t
|
||||
},
|
||||
)
|
||||
|
||||
//注册一个函数,获取struct tag里自定义的label作为字段名
|
||||
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
||||
name := fld.Tag.Get("label")
|
||||
return name
|
||||
})
|
||||
//验证器注册翻译器
|
||||
zh_translations.RegisterDefaultTranslations(validate, trans)
|
||||
_ = zh_translations.RegisterDefaultTranslations(validate, trans)
|
||||
errValidate := validate.Struct(request)
|
||||
|
||||
if errValidate != nil {
|
||||
|
@ -127,6 +152,34 @@ func GenRequest(c *gin.Context, request interface{}) (msgs []string, err error)
|
|||
return
|
||||
}
|
||||
|
||||
func ValidApiData(dataByte []byte, validStruct interface{}) (msgs []string, err error) {
|
||||
validate := validator.New()
|
||||
err = json.Unmarshal(dataByte, validStruct)
|
||||
if err != nil {
|
||||
err = errors.New(errorcode.GetMsg(errorcode.ParamError, ""))
|
||||
}
|
||||
zh_ch := zh.New()
|
||||
uni := ut.New(zh_ch)
|
||||
trans, _ := uni.GetTranslator("zh")
|
||||
//注册一个函数,获取struct tag里自定义的label作为字段名
|
||||
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
||||
name := fld.Tag.Get("label")
|
||||
return name
|
||||
})
|
||||
//验证器注册翻译器
|
||||
_ = zh_translations.RegisterDefaultTranslations(validate, trans)
|
||||
errValidate := validate.Struct(validStruct)
|
||||
if errValidate != nil {
|
||||
// 如果有错误,打印出来
|
||||
for _, v := range errValidate.(validator.ValidationErrors) {
|
||||
msgs = append(msgs, v.Translate(trans))
|
||||
}
|
||||
err = errors.New(errorcode.GetMsg(errorcode.ParamError, ""))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 重复读取body
|
||||
func ReadBody(c *gin.Context) (body []byte, err error) {
|
||||
body, err = ioutil.ReadAll(c.Request.Body)
|
||||
|
@ -142,6 +195,28 @@ func GetRequest(c *gin.Context) interface{} {
|
|||
return request
|
||||
}
|
||||
|
||||
func GetAppCheckInfo(c *gin.Context) interface{} {
|
||||
request, exists := c.Get("appCheckInfo")
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
// 获取OutTradeNo
|
||||
func GetOutTradeNo(c *gin.Context) string {
|
||||
outTradeNo, _ := c.Get("OutTradeNo")
|
||||
if outTradeNo == nil {
|
||||
return ""
|
||||
}
|
||||
return outTradeNo.(string)
|
||||
}
|
||||
|
||||
func GetApiLogId(c *gin.Context) (interface{}, bool) {
|
||||
request, exists := c.Get("log")
|
||||
return request, exists
|
||||
}
|
||||
|
||||
func HandRes(c *gin.Context, data interface{}, err error) {
|
||||
if err == nil {
|
||||
Success(c, data, "")
|
||||
|
@ -175,3 +250,40 @@ func Frequence(key string) bool {
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义验证器
|
||||
func phoneValidation(fl validator.FieldLevel) bool {
|
||||
phone := fl.Field().String()
|
||||
if phone == "" {
|
||||
return true
|
||||
}
|
||||
// 使用正则表达式验证手机号
|
||||
phoneRegex := `^1[3-9]\d{9}$`
|
||||
reg := regexp.MustCompile(phoneRegex)
|
||||
return reg.MatchString(phone)
|
||||
}
|
||||
|
||||
// 管理后台,获取用户id
|
||||
func GetAdminId(c *gin.Context) int {
|
||||
userIdStr, _ := c.Get(common.ADMIN_USER_ID)
|
||||
if userIdStr != nil {
|
||||
var userId, _ = strconv.Atoi(userIdStr.(string))
|
||||
return userId
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// 获取对应数据权限中拥有用户数据ID
|
||||
func GetAdminUserIncludeUsers(c *gin.Context) string {
|
||||
name, _ := c.Get(common.ADMIN_USER_INCLUDEUSERS)
|
||||
if name != nil {
|
||||
var temp, _ = name.(string)
|
||||
return temp
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ErrWithCode(c *gin.Context, code int) {
|
||||
Error(c, code, errorcode.GetMsg(code, c.GetHeader("local")))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package front
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay"
|
||||
"github.com/gin-gonic/gin"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func PayUrl(c *gin.Context) {
|
||||
var res front.ApiResponse
|
||||
req := controllers.GetRequest(c).(*front.PayReqs)
|
||||
c.Set("OutTradeNo", req.OutTradeNo)
|
||||
|
||||
appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck)
|
||||
check := thirdpay.ThirdPayInfoCheck(c.Request.Context(), req, appCheckInfo, c.ClientIP())
|
||||
if check.CheckCode != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, check.CheckCode)
|
||||
return
|
||||
}
|
||||
check.CheckOrderPay()
|
||||
if check.CheckCode != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, check.CheckCode)
|
||||
return
|
||||
}
|
||||
pay := thirdpay.ThirdPayUrl(check)
|
||||
if pay.PayCode != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, pay.PayCode)
|
||||
return
|
||||
}
|
||||
|
||||
res.Order = thirdpay.NewOrdersResp(pay.Order)
|
||||
res.Url = pay.Url
|
||||
controllers.ApiRes(c, res, pay.PayCode)
|
||||
return
|
||||
}
|
||||
|
||||
func Refund(c *gin.Context) {
|
||||
req := controllers.GetRequest(c).(*front.RefundReqs)
|
||||
c.Set("OutTradeNo", req.OutTradeNo)
|
||||
|
||||
appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck)
|
||||
refund := thirdpay.ThirdPayRefund(c.Request.Context(), req, appCheckInfo, c.ClientIP())
|
||||
if refund.PayCode != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, refund.PayCode)
|
||||
}
|
||||
data := thirdpay.NewOrdersResp(refund.Order)
|
||||
var res front.ApiResponse
|
||||
res.Order = data
|
||||
controllers.ApiRes(c, res, refund.PayCode)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// 查询订单
|
||||
func QueryOrder(c *gin.Context) {
|
||||
req := controllers.GetRequest(c).(*front.QueryReqs)
|
||||
c.Set("OutTradeNo", req.OutTradeNo)
|
||||
|
||||
appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck)
|
||||
// 查询订单表
|
||||
order := ordersmodel.Orders{
|
||||
OutTradeNo: req.OutTradeNo,
|
||||
AppId: req.AppId,
|
||||
MerchantId: appCheckInfo.App.MerchantId,
|
||||
}
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"out_trade_no": order.OutTradeNo}, builder.Eq{"app_id": order.AppId})
|
||||
_, code := services.OrderFindOne(&order, cond)
|
||||
if code != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, code)
|
||||
return
|
||||
}
|
||||
data := thirdpay.NewOrdersResp(&order)
|
||||
var res front.ApiResponse
|
||||
res.Order = data
|
||||
controllers.ApiRes(c, res, errorcode.Success)
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package front
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/third/paymentService"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
"github.com/go-pay/gopay/wechat/v3"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"strconv"
|
||||
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// WxCallback 微信支付回调
|
||||
func WxCallback(c *gin.Context) {
|
||||
logger.Info(c, "WxCallback-回调数据", c.Request)
|
||||
payChannelId := c.Param("payChannelId")
|
||||
logger.Info(c, "WxCallback-回调数据payChannelId", payChannelId)
|
||||
if payChannelId == "" {
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
// 查询应用下的支付配置
|
||||
var payChannelModel paychannelmodel.PayChannel
|
||||
payChannelIdInt, _ := strconv.Atoi(payChannelId)
|
||||
payChannelModel.Id = int64(payChannelIdInt)
|
||||
code := services.PayChannelGet(&payChannelModel)
|
||||
if code == errorcode.PayChannelNotFound {
|
||||
logger.Error(c, "AliCallback-回调数据未获取到支付配置,404")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
if payChannelModel.ChannelType != common.PAY_CHANNEL_WECHAT_H5 {
|
||||
logger.Error(c, "WxCallback-回调数据解析支付配置错误,查询的数据不是当前渠道")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
var wxConfig paymentService.WxPay
|
||||
err := json.Unmarshal([]byte(payChannelModel.ExtJson), &wxConfig)
|
||||
if err != nil {
|
||||
logger.Error(c, "WxCallback-回调数据解析支付配置错误", fmt.Sprintf("错误原因:%s", err.Error()))
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
if wxConfig.ApiV3Key == "" || wxConfig.MchId == "" || wxConfig.PrivateKey == "" || wxConfig.SerialNo == "" {
|
||||
logger.Error(c, "WxCallback-回调数据解析支付配置错误,解析出来的信息为空")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
wxConfig.AppId = payChannelModel.AppId
|
||||
|
||||
notifyReq, err := wechat.V3ParseNotify(c.Request)
|
||||
if err != nil {
|
||||
logger.Error(c, "WxCallback-回调数据验签失败", err.Error())
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
notifyReqJson, _ := json.Marshal(notifyReq)
|
||||
logger.Info(c, "WxCallback-解析微信回调请求的参数到 V3NotifyReq 结构体", string(notifyReqJson))
|
||||
err = paymentService.WxPayCallBack(notifyReq, wxConfig)
|
||||
if err != nil {
|
||||
logger.Error(c, "WxCallback-回调执行失败,失败原因:", err.Error())
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})
|
||||
return
|
||||
}
|
||||
|
||||
// AliCallback 支付宝支付回调
|
||||
func AliCallback(c *gin.Context) {
|
||||
logger.Info(c, "AliCallback-回调数据", c.Request)
|
||||
payChannelId := c.Param("payChannelId")
|
||||
logger.Info(c, "AliCallback-回调数据APPID", payChannelId)
|
||||
if payChannelId == "" {
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
// 查询应用下的支付配置
|
||||
var payChannelModel paychannelmodel.PayChannel
|
||||
payChannelIdInt, _ := strconv.Atoi(payChannelId)
|
||||
payChannelModel.Id = int64(payChannelIdInt)
|
||||
code := services.PayChannelGet(&payChannelModel)
|
||||
if code == errorcode.PayChannelNotFound {
|
||||
logger.Error(c, "AliCallback-回调数据未获取到支付配置,404")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
if payChannelModel.ChannelType != common.PAY_CHANNEL_ALIPAY_WEB {
|
||||
logger.Error(c, "AliCallback-回调数据解析支付配置错误,查询的数据不是当前渠道")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
var aliConfig paymentService.AliPay
|
||||
err := json.Unmarshal([]byte(payChannelModel.ExtJson), &aliConfig)
|
||||
if err != nil {
|
||||
logger.Error(c, "AliCallback-回调数据解析支付配置错误", fmt.Sprintf("错误原因:%s", err.Error()))
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
if aliConfig.AlipayPublicCert == "" || aliConfig.PrivateKey == "" || aliConfig.AppPublicCert == "" || aliConfig.AlipayRootCert == "" {
|
||||
logger.Error(c, "AliCallback-回调数据解析支付配置错误,解析出来的信息为空")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
aliConfig.AppId = payChannelModel.AppId
|
||||
|
||||
notifyReq, err := alipay.ParseNotifyToBodyMap(c.Request) // c.Request 是 gin 框架的写法
|
||||
if err != nil {
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
notifyReqJson, _ := json.Marshal(notifyReq)
|
||||
logger.Info(c, "AliCallback-解析支付宝支付异步通知的参数到BodyMap", string(notifyReqJson))
|
||||
err = paymentService.ALiCallBack(notifyReq, aliConfig)
|
||||
if err != nil {
|
||||
logger.Error(c, "AliCallback-回调执行失败,失败原因:", err.Error())
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
c.String(http.StatusOK, "%s", "success")
|
||||
return
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package domains
|
||||
|
||||
type Filter struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type ProductFilter struct {
|
||||
Page int `json:"page" form:"page"`
|
||||
PageSize int `json:"page_size" form:"page_size"`
|
||||
ProductName string `json:"product_name" form:"product_name"`
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package domains
|
||||
|
||||
import "time"
|
||||
|
||||
type Product struct {
|
||||
Id int
|
||||
ProductName string
|
||||
ProductType int
|
||||
PacketRule int
|
||||
ProductKind int
|
||||
Amount string
|
||||
CouponType int
|
||||
IsSuperposition int
|
||||
TemplateId int
|
||||
Status int
|
||||
IsNeedBill int
|
||||
CreateTime time.Time
|
||||
SupplierProductId int64
|
||||
SupplierProductName string
|
||||
|
||||
Creator string
|
||||
UpdateTime time.Time
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AppListRequest struct {
|
||||
Id int64 `json:"id" form:"id"`
|
||||
MerchantId int64 `json:"merchant_id" form:"merchant_id" validate:"required" label:"商户ID"`
|
||||
entities.PageRequest
|
||||
}
|
||||
|
||||
type AppResponse struct {
|
||||
Id int64 `json:"id"`
|
||||
MerchantId int64 `json:"merchant_id"`
|
||||
AppName string `json:"app_name"`
|
||||
AppRemark string `json:"app_remark"`
|
||||
Status int32 `json:"status"`
|
||||
KeyType int32 `json:"key_type"`
|
||||
PublicKey string `json:"public_key"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
MerchantPublicKey string `json:"merchant_public_key"`
|
||||
CreateTime string `json:"create_time"`
|
||||
WhiteIp string `json:"white_ip"`
|
||||
NotifyUrl string `json:"notify_url"`
|
||||
}
|
||||
|
||||
func (a *AppResponse) ResponseFromDb(db appmodel.App) {
|
||||
a.Id = db.Id
|
||||
a.MerchantId = db.MerchantId
|
||||
a.AppName = db.AppName
|
||||
a.AppRemark = db.AppRemark
|
||||
a.Status = db.Status
|
||||
a.KeyType = db.KeyType
|
||||
a.PublicKey = db.PublicKey
|
||||
a.PrivateKey = db.PrivateKey
|
||||
a.MerchantPublicKey = db.MerchantPublicKey
|
||||
a.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05")
|
||||
a.WhiteIp = db.WhiteIp
|
||||
a.NotifyUrl = db.NotifyUrl
|
||||
}
|
||||
|
||||
type AppCreateRequest struct {
|
||||
MerchantId int64 `json:"merchant_id" validate:"required" label:"商户ID"`
|
||||
AppName string `json:"app_name" validate:"required" label:"应用名称"`
|
||||
AppRemark string `json:"app_remark" label:"应用备注"`
|
||||
Status int32 `json:"status" validate:"oneof=0 1 2" label:"应用状态"`
|
||||
KeyType int32 `json:"key_type" validate:"required" label:"应用密钥类型"`
|
||||
PublicKey string `json:"public_key" validate:"required" label:"应用公钥"`
|
||||
PrivateKey string `json:"private_key" validate:"required" label:"应用私钥"`
|
||||
MerchantPublicKey string `json:"merchant_public_key" label:"商户公钥"`
|
||||
WhiteIp string `json:"white_ip"`
|
||||
NotifyUrl string `json:"notify_url" validate:"required" label:"通知地址"`
|
||||
}
|
||||
|
||||
func (a *AppCreateRequest) RequestToDb() (db appmodel.App, err error) {
|
||||
// 判断通知地址url是否合法
|
||||
if a.NotifyUrl == "" || strings.HasPrefix(a.NotifyUrl, "http://") || strings.HasPrefix(a.NotifyUrl, "https://") {
|
||||
db.MerchantId = a.MerchantId
|
||||
db.AppName = a.AppName
|
||||
db.AppRemark = a.AppRemark
|
||||
db.Status = a.Status
|
||||
db.KeyType = a.KeyType
|
||||
db.PublicKey = a.PublicKey
|
||||
db.PrivateKey = a.PrivateKey
|
||||
db.MerchantPublicKey = a.MerchantPublicKey
|
||||
db.WhiteIp = a.WhiteIp
|
||||
db.NotifyUrl = a.NotifyUrl
|
||||
} else {
|
||||
err = errors.New("通知地址格式不正确")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type AppUpdateRequest struct {
|
||||
Id int64 `json:"id" validate:"required" label:"应用ID"`
|
||||
AppName string `json:"app_name" label:"应用名称"`
|
||||
AppRemark string `json:"app_remark" label:"应用备注"`
|
||||
Status int32 `json:"status" label:"应用状态"`
|
||||
KeyType int32 `json:"key_type" label:"应用密钥类型"`
|
||||
PublicKey string `json:"public_key" label:"应用公钥"`
|
||||
PrivateKey string `json:"private_key" label:"应用私钥"`
|
||||
MerchantPublicKey string `json:"merchant_public_key" label:"商户公钥"`
|
||||
WhiteIp string `json:"white_ip"`
|
||||
NotifyUrl string `json:"notify_url"`
|
||||
}
|
||||
|
||||
func (a *AppUpdateRequest) RequestToDb() (db appmodel.App, err error) {
|
||||
// 判断通知地址url是否合法
|
||||
if a.NotifyUrl == "" || strings.HasPrefix(a.NotifyUrl, "http://") || strings.HasPrefix(a.NotifyUrl, "https://") {
|
||||
db.Id = a.Id
|
||||
db.AppName = a.AppName
|
||||
db.AppRemark = a.AppRemark
|
||||
db.Status = a.Status
|
||||
db.KeyType = a.KeyType
|
||||
db.PublicKey = a.PublicKey
|
||||
db.PrivateKey = a.PrivateKey
|
||||
db.MerchantPublicKey = a.MerchantPublicKey
|
||||
db.WhiteIp = a.WhiteIp
|
||||
db.NotifyUrl = a.NotifyUrl
|
||||
} else {
|
||||
err = errors.New("通知地址格式不正确")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type GenerateDecryptKeyRequest struct {
|
||||
KeyType int32 `json:"key_type" form:"key_type" label:"密钥类型"`
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
)
|
||||
|
||||
type MerchantListRequest struct {
|
||||
entities.PageRequest
|
||||
Name string `form:"name"`
|
||||
Contact string `form:"contact"`
|
||||
Phone string `form:"phone"`
|
||||
GroupInfo string
|
||||
}
|
||||
|
||||
type MerchantResponse struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Contact string `json:"contact"`
|
||||
Phone string `json:"phone"`
|
||||
Remark string `json:"remark"`
|
||||
CreateTime string `json:"create_time"`
|
||||
}
|
||||
|
||||
func (m *MerchantResponse) ResponseFromDb(db merchantmodel.Merchant) {
|
||||
m.Id = db.Id
|
||||
m.Name = db.Name
|
||||
m.Contact = db.Contact
|
||||
m.Phone = db.Phone
|
||||
m.Remark = db.Remark
|
||||
m.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
type MerchantCreateRequest struct {
|
||||
Name string `json:"name" validate:"required" label:"商户名称"`
|
||||
Contact string `json:"contact" validate:"required" label:"联系人"`
|
||||
Phone string `json:"phone" validate:"required,phoneValidation" label:"联系电话"`
|
||||
Remark string `json:"remark" label:"备注"`
|
||||
Creator int
|
||||
}
|
||||
|
||||
func (m *MerchantCreateRequest) RequestToDb() (db merchantmodel.Merchant) {
|
||||
db.Name = m.Name
|
||||
db.Contact = m.Contact
|
||||
db.Phone = m.Phone
|
||||
db.Remark = m.Remark
|
||||
db.Creator = m.Creator
|
||||
return db
|
||||
}
|
||||
|
||||
type MerchantUpdateRequest struct {
|
||||
Id int64 `json:"id" validate:"required" label:"商户ID"`
|
||||
Name string `json:"name"`
|
||||
Contact string `json:"contact"`
|
||||
Phone string `json:"phone" validate:"phoneValidation" label:"联系电话"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (m *MerchantUpdateRequest) RequestToDb() (db merchantmodel.Merchant) {
|
||||
db.Id = m.Id
|
||||
db.Name = m.Name
|
||||
db.Contact = m.Contact
|
||||
db.Phone = m.Phone
|
||||
db.Remark = m.Remark
|
||||
return db
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/ordercallbacklogmodel"
|
||||
"PaymentCenter/app/models/orderrequestlogmodel"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/models/orderthirdpaylogmodel"
|
||||
"PaymentCenter/app/utils"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
type OrderListRequest struct {
|
||||
Id int64 `json:"id" form:"id"`
|
||||
MerchantId int64 `json:"merchant_id" form:"merchant_id"`
|
||||
PayChannelId int64 `json:"pay_channel_id" form:"pay_channel_id"`
|
||||
AppId int64 `json:"app_id" form:"app_id"`
|
||||
OutTradeNo string `json:"out_trade_no" form:"out_trade_no"`
|
||||
Status int `json:"status" form:"status"`
|
||||
OrderType int `json:"order_type" form:"order_type"`
|
||||
StartTime string `json:"start_time" form:"start_time"`
|
||||
EndTime string `json:"end_time" form:"end_time"`
|
||||
entities.PageRequest
|
||||
}
|
||||
type OrderList struct {
|
||||
Id int64 `json:"id"`
|
||||
MerchantId int64 `json:"merchant_id"`
|
||||
PayChannelId int64 `json:"pay_channel_id"`
|
||||
AppId int64 `json:"app_id"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
Status int `json:"status"`
|
||||
OrderType int `json:"order_type"`
|
||||
StartTime time.Time `json:"start_time"`
|
||||
EndTime time.Time `json:"end_time"`
|
||||
entities.PageRequest
|
||||
}
|
||||
|
||||
func (o *OrderListRequest) ValidateRequest() (r OrderList, err error) {
|
||||
if o.StartTime != "" {
|
||||
r.StartTime, err = utils.StrToTimeShanghai(o.StartTime)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "时间格式错误")
|
||||
return
|
||||
}
|
||||
}
|
||||
if o.EndTime != "" {
|
||||
r.EndTime, err = utils.StrToTimeShanghai(o.EndTime)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "时间格式错误")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
r.Id = o.Id
|
||||
r.MerchantId = o.MerchantId
|
||||
r.PayChannelId = o.PayChannelId
|
||||
r.AppId = o.AppId
|
||||
r.OutTradeNo = o.OutTradeNo
|
||||
r.Status = o.Status
|
||||
r.OrderType = o.OrderType
|
||||
r.PageRequest = o.PageRequest
|
||||
r.SetDefault()
|
||||
return
|
||||
}
|
||||
|
||||
type OrdersResponse struct {
|
||||
Id int64 `json:"id"`
|
||||
MerchantId int64 `json:"merchant_id"`
|
||||
PayChannelId int64 `json:"pay_channel_id"`
|
||||
AppId int64 `json:"app_id"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
Status int `json:"status"`
|
||||
OrderType int `json:"order_type"`
|
||||
Amount int `json:"amount"`
|
||||
PayerTotal int `json:"payer_total"`
|
||||
ExtJson string `json:"ext_json"`
|
||||
CreateTime string `json:"create_time"`
|
||||
UpdateTime string `json:"update_time"`
|
||||
MerchantName string `json:"merchant_name"`
|
||||
PayName string `json:"pay_name"`
|
||||
AppName string `json:"app_name"`
|
||||
}
|
||||
|
||||
func (o *OrdersResponse) ResponseFromDb(db ordersmodel.OrdersBackendList) {
|
||||
o.Id = db.Id
|
||||
o.MerchantId = db.MerchantId
|
||||
o.PayChannelId = db.PayChannelId
|
||||
o.AppId = db.AppId
|
||||
o.OutTradeNo = db.OutTradeNo
|
||||
o.Status = db.Status
|
||||
o.OrderType = db.OrderType
|
||||
o.Amount = db.Amount
|
||||
o.PayerTotal = db.PayerTotal
|
||||
o.ExtJson = db.ExtJson
|
||||
o.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05")
|
||||
o.UpdateTime = db.UpdateTime.Format("2006-01-02 15:04:05")
|
||||
o.MerchantName = db.MerchantName
|
||||
o.PayName = db.PayName
|
||||
o.AppName = db.AppName
|
||||
}
|
||||
|
||||
type OrderLogsListRequest struct {
|
||||
Id int64 `json:"id" form:"id"`
|
||||
OrderId int64 `json:"order_id" form:"order_id"`
|
||||
AppId int64 `json:"app_id" form:"app_id"`
|
||||
OutTradeNo string `json:"out_trade_no" form:"out_trade_no"`
|
||||
entities.PageRequest
|
||||
}
|
||||
|
||||
type OrderRequestLogResponse struct {
|
||||
Id int64 `json:"id"`
|
||||
AppId int64 `json:"app_id"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
Url string `json:"url"`
|
||||
MerchantRequest string `json:"merchant_request"`
|
||||
MerchantResponse string `json:"merchant_response"`
|
||||
CreateTime string `json:"create_time"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func (o *OrderRequestLogResponse) ResponseFromDb(db orderrequestlogmodel.OrderRequestLog) {
|
||||
o.Id = db.Id
|
||||
o.AppId = db.AppId
|
||||
o.OutTradeNo = db.OutTradeNo
|
||||
o.IpAddress = db.IpAddress
|
||||
o.Url = db.URL
|
||||
o.Status = db.Status
|
||||
o.MerchantRequest = db.MerchantRequest
|
||||
o.MerchantResponse = db.MerchantResponse
|
||||
o.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
type OrderThirdLogResponse struct {
|
||||
Id int64 `json:"id"`
|
||||
OrderId int64 `json:"order_id"`
|
||||
|
||||
CreateTime string `json:"create_time"`
|
||||
PayCallback string `json:"pay_callback"`
|
||||
Status int `json:"status"`
|
||||
PayParam string `json:"pay_param"`
|
||||
MerchantCallback string `json:"merchant_callback"`
|
||||
}
|
||||
|
||||
func (o *OrderThirdLogResponse) ResponseFromDb(db orderthirdpaylogmodel.OrderThirdPayLog) {
|
||||
o.Id = db.Id
|
||||
o.OrderId = db.OrderId
|
||||
o.PayCallback = db.PayCallback
|
||||
o.Status = db.Status
|
||||
o.PayParam = db.PayParam
|
||||
o.MerchantCallback = db.MerchantCallback
|
||||
o.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
type OrderCallbackLogResponse struct {
|
||||
Id int64 `json:"id"`
|
||||
OrderId int64 `json:"order_id"`
|
||||
MerchantRequest string `json:"merchant_request"`
|
||||
Status int `json:"status"`
|
||||
MerchantResponse string `json:"merchant_response"`
|
||||
CreateTime string `json:"create_time"`
|
||||
}
|
||||
|
||||
func (o *OrderCallbackLogResponse) ResponseFromDb(db ordercallbacklogmodel.OrderCallbackLog) {
|
||||
o.Id = db.Id
|
||||
o.OrderId = db.OrderId
|
||||
o.MerchantRequest = db.MerchantRequest
|
||||
o.Status = db.Status
|
||||
o.MerchantResponse = db.MerchantResponse
|
||||
o.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05")
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/utils"
|
||||
"encoding/json"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type PayChannelResponse struct {
|
||||
Id int64 `json:"id"`
|
||||
PayName string `json:"pay_name"`
|
||||
MerchantId int64 `json:"merchant_id"`
|
||||
ChannelType int `json:"channel_type"`
|
||||
AppId string `json:"app_id"`
|
||||
ExpireTime string `json:"expire_time"`
|
||||
CreateTime string `json:"create_time"`
|
||||
AliPayChannel *AliPayChannel `json:"ali_pay_channel,omitempty"`
|
||||
WechatPayChannel *WechatPayChannel `json:"wechat_pay_channel,omitempty"`
|
||||
}
|
||||
|
||||
func (p *PayChannelResponse) ResponseFromDb(db paychannelmodel.PayChannel) {
|
||||
p.Id = db.Id
|
||||
p.PayName = db.PayName
|
||||
p.MerchantId = db.MerchantId
|
||||
p.ChannelType = db.ChannelType
|
||||
p.AppId = db.AppId
|
||||
if db.ExpireTime.IsZero() {
|
||||
p.ExpireTime = ""
|
||||
} else {
|
||||
p.ExpireTime = db.ExpireTime.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if db.CreateTime.IsZero() {
|
||||
p.CreateTime = ""
|
||||
} else {
|
||||
p.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
switch db.ChannelType {
|
||||
case common.PAY_CHANNEL_WECHAT_H5, common.PAY_CHANNEL_WECHAT_JSAPI, common.PAY_CHANNEL_WECHAT_NATIVE, common.PAY_CHANNEL_WECHAT_APP, common.PAY_CHANNEL_WECHAT_MINI:
|
||||
_ = json.Unmarshal([]byte(db.ExtJson), &p.WechatPayChannel)
|
||||
case common.PAY_CHANNEL_ALIPAY_JSAPI, common.PAY_CHANNEL_ALIPAY_WEB, common.PAY_CHANNEL_ALIPAY_MINI:
|
||||
_ = json.Unmarshal([]byte(db.ExtJson), &p.AliPayChannel)
|
||||
}
|
||||
}
|
||||
|
||||
type PayChannelCreateRequest struct {
|
||||
PayName string `json:"pay_name" validate:"required" label:"支付渠道名称"`
|
||||
MerchantId int64 `json:"merchant_id" validate:"required" label:"商户ID"`
|
||||
ChannelType int `json:"channel_type" validate:"required" label:"支付渠道"` //支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||
AppId string `json:"app_id" validate:"required" label:"应用appId"`
|
||||
ExpireTime string `json:"expire_time"`
|
||||
AliPayChannel AliPayChannel `json:"ali_pay_channel,omitempty"`
|
||||
WechatPayChannel WechatPayChannel `json:"wechat_pay_channel,omitempty"`
|
||||
}
|
||||
|
||||
type WechatPayChannel struct {
|
||||
MchId string `json:"mch_id"` // 商户ID 或者服务商模式的 sp_mchid
|
||||
SerialNo string `json:"serial_no"` // 商户证书的证书序列号
|
||||
ApiV3Key string `json:"api_v_3_key"` // apiV3Key,商户平台获取
|
||||
PrivateKey string `json:"private_key"` // 私钥 apiclient_key.pem 读取后的内容
|
||||
}
|
||||
|
||||
type AliPayChannel struct {
|
||||
PrivateKey string `json:"private_key"` // 应用私钥
|
||||
AppPublicCert string `json:"app_public_cert"` // 应用公钥
|
||||
AlipayRootCert string `json:"alipay_root_cert"` // 支付宝根证书
|
||||
AlipayPublicCert string `json:"alipay_public_cert"` // 支付宝公钥
|
||||
}
|
||||
|
||||
func (p *PayChannelCreateRequest) RequestToDb() (db paychannelmodel.PayChannel, err error) {
|
||||
db.PayName = p.PayName
|
||||
db.MerchantId = p.MerchantId
|
||||
db.ChannelType = p.ChannelType
|
||||
db.AppId = p.AppId
|
||||
if p.ExpireTime != "" {
|
||||
db.ExpireTime, err = utils.StrToTimeShanghai(p.ExpireTime)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "时间格式错误")
|
||||
}
|
||||
}
|
||||
switch p.ChannelType {
|
||||
case common.PAY_CHANNEL_WECHAT_H5, common.PAY_CHANNEL_WECHAT_JSAPI, common.PAY_CHANNEL_WECHAT_NATIVE, common.PAY_CHANNEL_WECHAT_APP, common.PAY_CHANNEL_WECHAT_MINI:
|
||||
b, _ := json.Marshal(p.WechatPayChannel)
|
||||
db.ExtJson = string(b)
|
||||
case common.PAY_CHANNEL_ALIPAY_JSAPI, common.PAY_CHANNEL_ALIPAY_WEB, common.PAY_CHANNEL_ALIPAY_MINI:
|
||||
b, _ := json.Marshal(p.AliPayChannel)
|
||||
db.ExtJson = string(b)
|
||||
default:
|
||||
err = errors.New("支付渠道类型错误")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type PayChannelListRequest struct {
|
||||
Id int64 `json:"id" form:"id" `
|
||||
MerchantId int64 `json:"merchant_id" form:"merchant_id" validate:"required" label:"商户ID"`
|
||||
entities.PageRequest
|
||||
}
|
||||
|
||||
type PayChannelUpdateRequest struct {
|
||||
Id int64 `json:"id" validate:"required"`
|
||||
PayName string `json:"pay_name" validate:"required" label:"支付渠道名称"`
|
||||
ChannelType int `json:"channel_type" validate:"required" label:"支付渠道"` //支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||
AppId string `json:"app_id" validate:"required" label:"应用appId"`
|
||||
ExpireTime string `json:"expire_time"`
|
||||
AliPayChannel AliPayChannel `json:"ali_pay_channel,omitempty"`
|
||||
WechatPayChannel WechatPayChannel `json:"wechat_pay_channel,omitempty"`
|
||||
}
|
||||
|
||||
func (p PayChannelUpdateRequest) RequestToDb() (db paychannelmodel.PayChannel, err error) {
|
||||
db.Id = p.Id
|
||||
db.PayName = p.PayName
|
||||
db.ChannelType = p.ChannelType
|
||||
db.AppId = p.AppId
|
||||
if p.ExpireTime != "" {
|
||||
db.ExpireTime, err = utils.StrToTimeShanghai(p.ExpireTime)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "时间格式错误")
|
||||
}
|
||||
}
|
||||
switch p.ChannelType {
|
||||
case common.PAY_CHANNEL_WECHAT_H5, common.PAY_CHANNEL_WECHAT_JSAPI, common.PAY_CHANNEL_WECHAT_NATIVE, common.PAY_CHANNEL_WECHAT_APP, common.PAY_CHANNEL_WECHAT_MINI:
|
||||
b, _ := json.Marshal(p.WechatPayChannel)
|
||||
db.ExtJson = string(b)
|
||||
case common.PAY_CHANNEL_ALIPAY_JSAPI, common.PAY_CHANNEL_ALIPAY_WEB, common.PAY_CHANNEL_ALIPAY_MINI:
|
||||
b, _ := json.Marshal(p.AliPayChannel)
|
||||
db.ExtJson = string(b)
|
||||
default:
|
||||
err = errors.New("支付渠道类型错误")
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,15 +1,24 @@
|
|||
package entities
|
||||
|
||||
type IdRequest struct {
|
||||
Id int64 `json:"id"`
|
||||
Id int64 `json:"id" form:"id" valid:"Required"`
|
||||
}
|
||||
|
||||
type PageRequest struct {
|
||||
Page int64 `json:"page"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
Page int `json:"page" form:"page"`
|
||||
PageSize int `json:"page_size" form:"page_size"`
|
||||
}
|
||||
|
||||
func (p *PageRequest) SetDefault() {
|
||||
if p.Page == 0 {
|
||||
p.Page = 1
|
||||
}
|
||||
if p.PageSize == 0 {
|
||||
p.PageSize = 10
|
||||
}
|
||||
}
|
||||
|
||||
type PageRsp struct {
|
||||
Total int64 `json:"total"`
|
||||
Data []interface{} `json:"data"`
|
||||
Total int64 `json:"total"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package front
|
||||
|
||||
type ApiCommonBody struct {
|
||||
AppId int64 `json:"app_id" validate:"required"`
|
||||
Timestamp int64 `json:"timestamp" validate:"required"`
|
||||
}
|
||||
|
||||
type RequestBody struct {
|
||||
AppId int64 `json:"app_id" validate:"required"`
|
||||
Timestamp int64 `json:"timestamp" validate:"required"`
|
||||
Data string `json:"data" validate:"required"`
|
||||
Key string `json:"key" validate:"max=32"`
|
||||
}
|
||||
|
||||
type PayCommonReqBody struct {
|
||||
ApiCommonBody
|
||||
PayChannelId int64 `json:"pay_channel_id" validate:"required" label:"支付渠道"`
|
||||
Amount int `json:"amount" validate:"required" label:"支付金额,单位分"`
|
||||
ExtJson string `json:"ext_json" label:"扩展参数"`
|
||||
Desc string `json:"desc" validate:"max=100" label:"商品描述"`
|
||||
}
|
||||
|
||||
type PayReqs struct {
|
||||
PayCommonReqBody
|
||||
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
|
||||
}
|
||||
|
||||
type RefundReqs struct {
|
||||
PayCommonReqBody
|
||||
RefundOutTradeNo string `json:"refund_out_trade_no" label:"需要退款的外侧商户订单号"`
|
||||
RefundOrderId string `json:"refundOrder_id" label:"需要退款的平台订单号"`
|
||||
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
|
||||
}
|
||||
|
||||
type PayUrlResp struct {
|
||||
Order string `json:"order"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type QueryReqs struct {
|
||||
ApiCommonBody
|
||||
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
|
||||
}
|
||||
|
||||
// api 接口返回数据, 统一返回结构, order数据会进行加密
|
||||
type ApiResponse struct {
|
||||
Order interface{} `json:"order"`
|
||||
Url string `json:"url,omitempty"`
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package front
|
|
@ -4,12 +4,14 @@ import (
|
|||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
"PaymentCenter/app/http/requestmapping"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay/api"
|
||||
"PaymentCenter/app/utils"
|
||||
"context"
|
||||
"errors"
|
||||
"PaymentCenter/config"
|
||||
"encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/qit-team/snow-core/redis"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -59,20 +61,40 @@ func Cors() gin.HandlerFunc {
|
|||
|
||||
func AdminAuth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var token = c.GetHeader("token")
|
||||
//将token放入redis
|
||||
var playerId, err = redis.GetRedis().Get(context.Background(), utils.GetRealKey(common.TOKEN_Admin+token)).Result()
|
||||
if rs, errRedis := redis.GetRedis().SIsMember(context.Background(), "disabled_uids", playerId).Result(); errRedis == nil && rs {
|
||||
err = errors.New(errorcode.GetMsg(errorcode.NotFound, ""))
|
||||
redis.GetRedis().SRem(context.Background(), "disabled_uids", playerId)
|
||||
}
|
||||
if err == nil {
|
||||
c.Set("playerId", playerId)
|
||||
c.Next()
|
||||
return
|
||||
} else {
|
||||
controllers.HandCodeRes(c, nil, errorcode.Forbidden)
|
||||
clientIp := c.ClientIP()
|
||||
utils.Log(c, "请求地址clientIp", clientIp, config.GetConf().AdminGate)
|
||||
|
||||
if config.GetConf().Debug == false && !utils.SliceInStr(clientIp, config.GetConf().AdminGate) {
|
||||
c.Abort()
|
||||
controllers.HandCodeRes(c, nil, errorcode.Forbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var userName = c.GetHeader("User-Name")
|
||||
if userName != "" {
|
||||
c.Set(common.ADMIN_USER_NAME, userName)
|
||||
}
|
||||
var IncludeUsers = c.GetHeader("Include-Users")
|
||||
if IncludeUsers != "" {
|
||||
c.Set(common.ADMIN_USER_INCLUDEUSERS, IncludeUsers)
|
||||
}
|
||||
|
||||
var adminId = c.GetHeader("User-Id")
|
||||
// 测试环境直接放行
|
||||
if config.GetConf().Debug == true {
|
||||
c.Set(common.ADMIN_USER_ID, adminId)
|
||||
c.Next()
|
||||
} else {
|
||||
utils.Log(c, "请求header信息", "adminId="+adminId, "IncludeUsers="+IncludeUsers)
|
||||
// 正式环境校验
|
||||
if adminId != "" {
|
||||
c.Set(common.ADMIN_USER_ID, adminId)
|
||||
c.Next()
|
||||
} else {
|
||||
c.Abort()
|
||||
controllers.HandCodeRes(c, nil, errorcode.NotAuth)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,25 +103,98 @@ func ValidateRequest() gin.HandlerFunc {
|
|||
return func(c *gin.Context) {
|
||||
var path = c.FullPath()
|
||||
var handler func() interface{}
|
||||
|
||||
if strings.Index(path, "admin") >= 0 {
|
||||
handler = requestmapping.BackendRequestMap[path]
|
||||
} else {
|
||||
handler = requestmapping.FrontRequestMap[path]
|
||||
handler = requestmapping.FrontRequestMapBeforeDecrypt[path]
|
||||
}
|
||||
if handler == nil {
|
||||
utils.Log(c, "path", path)
|
||||
utils.Log(c, "path", path, "未找到handler")
|
||||
controllers.HandCodeRes(c, nil, errorcode.NotFound)
|
||||
} else {
|
||||
v := handler()
|
||||
msg, err := controllers.GenRequest(c, v)
|
||||
if err != nil {
|
||||
utils.Log(c, "path", path)
|
||||
controllers.Error(c, errorcode.ParamError, msg...)
|
||||
} else {
|
||||
c.Set("request", v)
|
||||
c.Next()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
v := handler()
|
||||
msg, err := controllers.GenRequest(c, v)
|
||||
if err != nil {
|
||||
utils.Log(c, "参数错误", "path=", path, "err=", err.Error(), "msg=", msg)
|
||||
controllers.Error(c, errorcode.ParamError, msg...)
|
||||
c.Abort()
|
||||
}
|
||||
c.Set("request", v)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func ValidatePayRequest() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var (
|
||||
path = c.FullPath()
|
||||
code int
|
||||
log_id int64
|
||||
)
|
||||
|
||||
var handler func() (interface{}, bool)
|
||||
requestData, err := utils.SonicApiDataToStruct(controllers.GetRequest(c), &front.RequestBody{})
|
||||
if err != nil {
|
||||
controllers.ApiRes(c, nil, errorcode.ParamError)
|
||||
return
|
||||
}
|
||||
requestDataStruct := requestData.(*front.RequestBody)
|
||||
|
||||
//判断时间
|
||||
//now := time.Now().UnixNano() / 1000000
|
||||
//if requestDataStruct.Timestamp > now || (config.GetConf().TimeOut != 0 && (now-requestDataStruct.Timestamp) > config.GetConf().TimeOut) {
|
||||
// controllers.ApiRes(c, nil, errorcode.RequestTimeOut)
|
||||
// return
|
||||
//}
|
||||
//获取app信息
|
||||
appCheck := services.GetAppCheck(requestDataStruct.AppId, c.ClientIP())
|
||||
//存入请求记录
|
||||
if appCheck.Code != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, appCheck.Code)
|
||||
return
|
||||
}
|
||||
//解密
|
||||
dataByte, errCode := api.DeCrypt(appCheck.App, requestDataStruct.Data, requestDataStruct.Key)
|
||||
if errCode != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, errCode)
|
||||
return
|
||||
}
|
||||
|
||||
//检查解密后的数据是否与请求一致
|
||||
reCheck := appCheck.ReCheckAfterDecrypt(dataByte, requestDataStruct)
|
||||
if !reCheck {
|
||||
controllers.ApiRes(c, nil, appCheck.GetCode())
|
||||
return
|
||||
}
|
||||
//表单验证
|
||||
|
||||
handler = requestmapping.FrontRequestMap[path]
|
||||
v, isSaveLog := handler()
|
||||
if isSaveLog {
|
||||
//记录请求日志
|
||||
log_id, code = services.AddRequestLog(dataByte, c.ClientIP(), path)
|
||||
if code != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, errCode)
|
||||
}
|
||||
}
|
||||
|
||||
c.Set("log", log_id)
|
||||
msg, err := controllers.ValidApiData(dataByte, v)
|
||||
if err != nil {
|
||||
utils.Log(c, "参数错误", "path=", path, "err=", err.Error(), "msg=", msg)
|
||||
controllers.ApiRes(c, nil, errorcode.ParamError, msg...)
|
||||
c.Abort()
|
||||
}
|
||||
err = json.Unmarshal(dataByte, &v)
|
||||
if err != nil {
|
||||
controllers.ApiRes(c, nil, errorcode.Forbidden)
|
||||
return
|
||||
}
|
||||
c.Set("request", v)
|
||||
c.Set("appCheckInfo", appCheck)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,32 @@
|
|||
package requestmapping
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
)
|
||||
|
||||
var BackendRequestMap = map[string]func() interface{}{
|
||||
|
||||
//common.ADMIN_V1 + "/product/create": func() interface{} {
|
||||
// return new(backend.ProductCreateRequest)
|
||||
//},
|
||||
// 商户
|
||||
common.ADMIN_V1 + "/merchant/create": func() interface{} { return new(backend.MerchantCreateRequest) },
|
||||
common.ADMIN_V1 + "/merchant/update": func() interface{} { return new(backend.MerchantUpdateRequest) },
|
||||
common.ADMIN_V1 + "/merchant/list": func() interface{} { return new(backend.MerchantListRequest) },
|
||||
common.ADMIN_V1 + "/merchant/delete": func() interface{} { return new(entities.IdRequest) },
|
||||
// 支付方式
|
||||
common.ADMIN_V1 + "/paychannel/create": func() interface{} { return new(backend.PayChannelCreateRequest) },
|
||||
common.ADMIN_V1 + "/paychannel/update": func() interface{} { return new(backend.PayChannelUpdateRequest) },
|
||||
common.ADMIN_V1 + "/paychannel/list": func() interface{} { return new(backend.PayChannelListRequest) },
|
||||
common.ADMIN_V1 + "/paychannel/delete": func() interface{} { return new(entities.IdRequest) },
|
||||
// 应用
|
||||
common.ADMIN_V1 + "/app/create": func() interface{} { return new(backend.AppCreateRequest) },
|
||||
common.ADMIN_V1 + "/app/update": func() interface{} { return new(backend.AppUpdateRequest) },
|
||||
common.ADMIN_V1 + "/app/list": func() interface{} { return new(backend.AppListRequest) },
|
||||
common.ADMIN_V1 + "/app/delete": func() interface{} { return new(entities.IdRequest) },
|
||||
common.ADMIN_V1 + "/app/decrypt": func() interface{} { return new(backend.GenerateDecryptKeyRequest) },
|
||||
// 订单
|
||||
common.ADMIN_V1 + "/order/list": func() interface{} { return new(backend.OrderListRequest) },
|
||||
common.ADMIN_V1 + "/order/log/request": func() interface{} { return new(backend.OrderLogsListRequest) },
|
||||
common.ADMIN_V1 + "/order/log/callback": func() interface{} { return new(backend.OrderLogsListRequest) },
|
||||
common.ADMIN_V1 + "/order/log/third": func() interface{} { return new(backend.OrderLogsListRequest) },
|
||||
}
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
package requestmapping
|
||||
|
||||
var FrontRequestMap = map[string]func() interface{}{
|
||||
//"/v1/login": func() interface{} {
|
||||
// return new(front.LoginRequest)
|
||||
//},
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
)
|
||||
|
||||
var FrontRequestMap = map[string]func() (validForm interface{}, isSaveLog bool){
|
||||
common.FRONT_V1 + "/pay/url": func() (interface{}, bool) { return new(front.PayReqs), true },
|
||||
common.FRONT_V1 + "/pay/refund": func() (interface{}, bool) { return new(front.RefundReqs), true },
|
||||
common.FRONT_V1 + "/pay/query": func() (interface{}, bool) { return new(front.QueryReqs), false },
|
||||
}
|
||||
|
||||
var FrontRequestMapBeforeDecrypt = map[string]func() interface{}{
|
||||
|
||||
common.FRONT_V1 + "/pay/url": func() interface{} { return new(front.RequestBody) },
|
||||
common.FRONT_V1 + "/pay/refund": func() interface{} { return new(front.RequestBody) },
|
||||
common.FRONT_V1 + "/pay/query": func() interface{} { return new(front.RequestBody) },
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package routes
|
|||
|
||||
import (
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/controllers/backend"
|
||||
"PaymentCenter/app/http/middlewares"
|
||||
"PaymentCenter/app/http/trace"
|
||||
"PaymentCenter/app/utils"
|
||||
|
@ -22,9 +23,36 @@ func RegisterAdminRoute(router *gin.Engine) {
|
|||
}
|
||||
}
|
||||
|
||||
//v1 := router.Group("/admin/api/v1")
|
||||
//{
|
||||
//
|
||||
//}
|
||||
v1 := router.Group("/pay/admin/api/v1", middlewares.AdminAuth(), middlewares.ValidateRequest())
|
||||
{
|
||||
// 商户管理
|
||||
merchant := v1.Group("/merchant")
|
||||
merchant.GET("/list", backend.MerchantList) // 商户列表
|
||||
merchant.POST("/create", backend.MerchantCreate) // 商户创建
|
||||
merchant.PUT("/update", backend.MerchantUpdate) // 商户更新
|
||||
merchant.DELETE("/delete", backend.MerchantDelete) // 商户删除
|
||||
// 支付方式
|
||||
pay := v1.Group("/paychannel")
|
||||
pay.GET("/list", backend.PayChannelList) // 支付方式列表
|
||||
pay.POST("/create", backend.PayChannelCreate) // 支付方式创建
|
||||
pay.PUT("/update", backend.PayChannelUpdate) // 支付方式更新
|
||||
pay.DELETE("/delete", backend.PayChannelDelete) // 支付方式删除
|
||||
|
||||
// 应用管理
|
||||
app := v1.Group("/app")
|
||||
app.GET("/list", backend.AppList) // 应用列表
|
||||
app.POST("/create", backend.AppCreate) // 应用创建
|
||||
app.PUT("/update", backend.AppUpdate) // 应用更新
|
||||
app.DELETE("/delete", backend.AppDelete) // 应用删除
|
||||
app.GET("/decrypt", backend.GenerateDecrypt) // 生成密钥对
|
||||
|
||||
// 订单
|
||||
order := v1.Group("/order")
|
||||
order.GET("/list", backend.OrderList) // 订单列表
|
||||
order.GET("/log/request", backend.OrderRequestLogsList) // 请求日志列表
|
||||
order.GET("/log/callback", backend.OrderCallbackLogsList) // 回调日志列表
|
||||
order.GET("/log/third", backend.OrderThirdLogsList) // 三方日志列表
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,17 +4,19 @@ package routes
|
|||
* 配置路由
|
||||
*/
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/http/controllers"
|
||||
"PaymentCenter/app/http/controllers/front"
|
||||
"PaymentCenter/app/http/middlewares"
|
||||
"PaymentCenter/app/http/trace"
|
||||
"PaymentCenter/app/utils/metric"
|
||||
"PaymentCenter/config"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
"github.com/swaggo/gin-swagger/swaggerFiles"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/qit-team/snow-core/http/middleware"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"github.com/swaggo/gin-swagger"
|
||||
"github.com/swaggo/gin-swagger/swaggerFiles"
|
||||
)
|
||||
|
||||
// api路由配置
|
||||
|
@ -43,17 +45,25 @@ func RegisterRoute(router *gin.Engine) {
|
|||
router.Use(middlewares.Cors())
|
||||
router.NoRoute(controllers.Error404)
|
||||
|
||||
//api版本
|
||||
//v1 := router.Group("/v1", middlewares.ValidateRequest())
|
||||
//{
|
||||
//
|
||||
//}
|
||||
//router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
||||
v1 := router.Group(common.FRONT_V1)
|
||||
{
|
||||
//回调处理
|
||||
notify := v1.Group("/notify")
|
||||
{
|
||||
notify.POST("/wx/:payChannelId", front.WxCallback)
|
||||
notify.POST("/ali/:payChannelId", front.AliCallback)
|
||||
}
|
||||
|
||||
pay := v1.Group("/pay", middlewares.ValidateRequest(), middlewares.ValidatePayRequest())
|
||||
{
|
||||
pay.POST("/url", front.PayUrl)
|
||||
pay.POST("/query", front.QueryOrder) //查询订单
|
||||
pay.POST("/refund", front.Refund)
|
||||
}
|
||||
}
|
||||
|
||||
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
||||
//router.GET("/hello", controllers.HelloHandler)
|
||||
//router.GET("/create", controllers.HelloCreateHandler)
|
||||
//router.GET("/update", controllers.UpdateHandler)
|
||||
//router.GET("/delete", controllers.DeleteHandler)
|
||||
//router.GET("/query", controllers.QueryHandler)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package appmodel
|
||||
|
||||
import (
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
m *AppModel
|
||||
)
|
||||
|
||||
// 实体
|
||||
type App struct {
|
||||
Id int64
|
||||
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
|
||||
AppName string `xorm:"'app_name' varchar(20)"`
|
||||
AppRemark string `xorm:"'app_remark' varchar(200)"`
|
||||
Status int32 `xorm:"'status' tinyint(2)"`
|
||||
KeyType int32 `xorm:"'key_type' tinyint(2)"`
|
||||
PublicKey string `xorm:"'public_key' varchar(1024)"`
|
||||
PrivateKey string `xorm:"'private_key' TEXT"`
|
||||
MerchantPublicKey string `xorm:"'merchant_public_key' varchar(1024)"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
|
||||
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
|
||||
NotifyUrl string `xorm:"'notify_url' varchar(128)"`
|
||||
WhiteIp string `xorm:"'white_ip' varchar(255)"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (m *App) TableName() string {
|
||||
return "app"
|
||||
}
|
||||
|
||||
// 私有化,防止被外部new
|
||||
type AppModel struct {
|
||||
db.Model //组合基础Model,集成基础Model的属性和方法
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
func GetInstance() *AppModel {
|
||||
once.Do(func() {
|
||||
m = new(AppModel)
|
||||
//m.DiName = "" //设置数据库实例连接,默认db.SingletonMain
|
||||
})
|
||||
return m
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package merchantmodel
|
||||
|
||||
import (
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
m *MerchantModel
|
||||
)
|
||||
|
||||
// 实体
|
||||
type Merchant struct {
|
||||
Id int64
|
||||
Name string `xorm:"'name' varchar(128)"`
|
||||
Contact string `xorm:"'contact' varchar(128)"`
|
||||
Phone string `xorm:"'phone' varchar(11)"`
|
||||
Remark string `xorm:"'remark' varchar(1024)"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
|
||||
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
|
||||
Creator int `xorm:"'creator' int(11)"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (m *Merchant) TableName() string {
|
||||
return "merchant"
|
||||
}
|
||||
|
||||
// 私有化,防止被外部new
|
||||
type MerchantModel struct {
|
||||
db.Model //组合基础Model,集成基础Model的属性和方法
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
func GetInstance() *MerchantModel {
|
||||
once.Do(func() {
|
||||
m = new(MerchantModel)
|
||||
//m.DiName = "" //设置数据库实例连接,默认db.SingletonMain
|
||||
})
|
||||
return m
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package ordercallbacklogmodel
|
||||
|
||||
import (
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
m *OrderCallbackLogModel
|
||||
)
|
||||
|
||||
// 实体
|
||||
type OrderCallbackLog struct {
|
||||
Id int64 `xorm:"'id' bigint(20) pk autoincr"`
|
||||
OrderId int64 `xorm:"'order_id' bigint(20)"`
|
||||
MerchantRequest string `xorm:"'merchant_request' JSON"`
|
||||
Status int `xorm:"'status' int(11)"`
|
||||
MerchantResponse string `xorm:"'merchant_response' JSON"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (m *OrderCallbackLog) TableName() string {
|
||||
return "order_callback_log"
|
||||
}
|
||||
|
||||
// 私有化,防止被外部new
|
||||
type OrderCallbackLogModel struct {
|
||||
db.Model //组合基础Model,集成基础Model的属性和方法
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
func GetInstance() *OrderCallbackLogModel {
|
||||
once.Do(func() {
|
||||
m = new(OrderCallbackLogModel)
|
||||
//m.DiName = "" //设置数据库实例连接,默认db.SingletonMain
|
||||
})
|
||||
return m
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package orderrequestlogmodel
|
||||
|
||||
import (
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
m *OrderRequestLogModel
|
||||
)
|
||||
|
||||
// 实体
|
||||
type OrderRequestLog struct {
|
||||
Id int64
|
||||
AppId int64 `xorm:"'app_id' bigint(20)"`
|
||||
OutTradeNo string `xorm:"'out_trade_no' varchar(50)"`
|
||||
IpAddress string `xorm:"'ip_address' varchar(16)"`
|
||||
URL string `xorm:"'url' varchar(100)"`
|
||||
MerchantRequest string `xorm:"'merchant_request' JSON"`
|
||||
MerchantResponse string `xorm:"'merchant_response' JSON"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
|
||||
Status int `xorm:"'status' TINYINT"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (m *OrderRequestLog) TableName() string {
|
||||
return "order_request_log"
|
||||
}
|
||||
|
||||
// 私有化,防止被外部new
|
||||
type OrderRequestLogModel struct {
|
||||
db.Model //组合基础Model,集成基础Model的属性和方法
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
func GetInstance() *OrderRequestLogModel {
|
||||
once.Do(func() {
|
||||
m = new(OrderRequestLogModel)
|
||||
//m.DiName = "" //设置数据库实例连接,默认db.SingletonMain
|
||||
})
|
||||
return m
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package ordersmodel
|
||||
|
||||
import (
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
m *OrdersModel
|
||||
)
|
||||
|
||||
// 实体
|
||||
type Orders struct {
|
||||
Id int64
|
||||
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
|
||||
PayChannelId int64 `xorm:"'pay_channel_id' bigint(20)"`
|
||||
AppId int64 `xorm:"'app_id' bigint(20)"`
|
||||
OutTradeNo string `xorm:"'out_trade_no' varchar(50)"`
|
||||
OrderType int `xorm:"'order_type' TINYINT"`
|
||||
RefundOrderId int64 `xorm:"'refund_order_id' bigint(20)"`
|
||||
Amount int `xorm:"'amount' int(11)"`
|
||||
PayerTotal int `xorm:"'payer_total' int(11)"`
|
||||
ExtJson string `xorm:"'ext_json' varchar(1024)"`
|
||||
Desc string `xorm:"'desc' varchar(100)"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
|
||||
Status int `xorm:"'status' TINYINT"`
|
||||
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
|
||||
}
|
||||
|
||||
type OrdersBackendList struct {
|
||||
Orders `xorm:"extends"`
|
||||
MerchantName string `xorm:"'merchant_name' varchar(128)"`
|
||||
PayName string `xorm:"'pay_name' varchar(128)"`
|
||||
AppName string `xorm:"'app_name' varchar(128)"`
|
||||
}
|
||||
type OrdersLeftPayChannelList struct {
|
||||
Orders `xorm:"extends"`
|
||||
ChannelType int `xorm:"'channel_type' int(11)"`
|
||||
AppId string `xorm:"'app_id' varchar(255)"`
|
||||
ExtJson string `xorm:"'ext_json' JSON"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (m *Orders) TableName() string {
|
||||
return "orders"
|
||||
}
|
||||
|
||||
// 私有化,防止被外部new
|
||||
type OrdersModel struct {
|
||||
db.Model //组合基础Model,集成基础Model的属性和方法
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
func GetInstance() *OrdersModel {
|
||||
once.Do(func() {
|
||||
m = new(OrdersModel)
|
||||
//m.DiName = "" //设置数据库实例连接,默认db.SingletonMain
|
||||
})
|
||||
return m
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package orderthirdpaylogmodel
|
||||
|
||||
import (
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
m *OrderThirdPayLogModel
|
||||
)
|
||||
|
||||
// 实体
|
||||
type OrderThirdPayLog struct {
|
||||
Id int64
|
||||
OrderId int64 `xorm:"'order_id' bigint(20)"`
|
||||
PayCallback string `xorm:"'pay_callback' JSON"`
|
||||
Status int `xorm:"'status' TINYINT"`
|
||||
PayParam string `xorm:"'pay_param' JSON"`
|
||||
MerchantCallback string `xorm:"'merchant_callback' JSON"`
|
||||
Type int `xorm:"'type' TINYINT"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (m *OrderThirdPayLog) TableName() string {
|
||||
return "order_third_pay_log"
|
||||
}
|
||||
|
||||
// 私有化,防止被外部new
|
||||
type OrderThirdPayLogModel struct {
|
||||
db.Model //组合基础Model,集成基础Model的属性和方法
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
func GetInstance() *OrderThirdPayLogModel {
|
||||
once.Do(func() {
|
||||
m = new(OrderThirdPayLogModel)
|
||||
//m.DiName = "" //设置数据库实例连接,默认db.SingletonMain
|
||||
})
|
||||
return m
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package paychannelmodel
|
||||
|
||||
import (
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
m *PayChannelModel
|
||||
)
|
||||
|
||||
// 实体
|
||||
type PayChannel struct {
|
||||
Id int64
|
||||
PayName string `xorm:"'pay_name' varchar(128)"`
|
||||
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
|
||||
ChannelType int `xorm:"'channel_type' tinyint(2)"`
|
||||
AppId string `xorm:"'app_id' varchar(255)"`
|
||||
ExtJson string `xorm:"'ext_json' JSON"`
|
||||
ExpireTime time.Time `xorm:"'expire_time' datetime"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
|
||||
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (m *PayChannel) TableName() string {
|
||||
return "pay_channel"
|
||||
}
|
||||
|
||||
// 私有化,防止被外部new
|
||||
type PayChannelModel struct {
|
||||
db.Model //组合基础Model,集成基础Model的属性和方法
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
func GetInstance() *PayChannelModel {
|
||||
once.Do(func() {
|
||||
m = new(PayChannelModel)
|
||||
//m.DiName = "" //设置数据库实例连接,默认db.SingletonMain
|
||||
})
|
||||
return m
|
||||
}
|
|
@ -14,7 +14,7 @@ func SingleTalk(tag uint64, ch interface{}, msg []byte) {
|
|||
// }
|
||||
// }
|
||||
// if !sendOk {
|
||||
// common.PikaTool.Zadd(utils.GetRealKey(common2.USER_MSG)+data.Msg.To, data, time.Now().Unix())
|
||||
// payCommon.PikaTool.Zadd(utils.GetRealKey(common2.USER_MSG)+data.Msg.To, data, time.Now().Unix())
|
||||
// }
|
||||
//}
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/services/apicrypt"
|
||||
"PaymentCenter/app/utils"
|
||||
"github.com/bytedance/sonic"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AppCheck struct {
|
||||
AppId int64
|
||||
Ip string
|
||||
App *appmodel.App
|
||||
Code int
|
||||
}
|
||||
|
||||
func NewAppCheck(app *appmodel.App) *AppCheck {
|
||||
return &AppCheck{
|
||||
App: app,
|
||||
Code: errorcode.Success,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AppCheck) IpCheck(ip string) bool {
|
||||
if a.App.WhiteIp == "" {
|
||||
return true
|
||||
}
|
||||
if !utils.ContainsString(strings.Split(a.App.WhiteIp, ","), ip) {
|
||||
a.Code = errorcode.AppIpNotAllow
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *AppCheck) Check() *AppCheck {
|
||||
|
||||
if a.App.Status == common.STATUS_DISABLED {
|
||||
a.Code = errorcode.AppDisabled
|
||||
return a
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AppCheck) GetCode() int {
|
||||
return a.Code
|
||||
}
|
||||
|
||||
func (a *AppCheck) Crypt() (cryptFunc func(app *appmodel.App) apicrypt.ApiCrypt) {
|
||||
var (
|
||||
ok bool
|
||||
)
|
||||
if cryptFunc, ok = apicrypt.ApiCryptMap[a.App.KeyType]; !ok {
|
||||
a.Code = errorcode.AppNotFound
|
||||
return nil
|
||||
}
|
||||
return cryptFunc
|
||||
}
|
||||
|
||||
func (a *AppCheck) ReCheckAfterDecrypt(data []byte, requestData *front.RequestBody) bool {
|
||||
var requestCommonData front.ApiCommonBody
|
||||
if err := sonic.Unmarshal(data, &requestCommonData); err != nil {
|
||||
a.Code = errorcode.ParamError
|
||||
return false
|
||||
}
|
||||
if requestCommonData.AppId != requestData.AppId || requestCommonData.Timestamp != requestData.Timestamp {
|
||||
a.Code = errorcode.AppDecryptDataDiscrepancy
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package apicrypt
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/utils/encrypt/rsa"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
func NewRsa(app *appmodel.App) ApiCrypt {
|
||||
return &Rsa{
|
||||
App: app,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rsa) Encrypt(data string) (encryptData []byte, errCode int) {
|
||||
if r.App.PublicKey == "" {
|
||||
return nil, errorcode.AppRsaEncryptKeyNotFound
|
||||
}
|
||||
publicKeyPEM := `-----BEGIN PUBLIC KEY-----
|
||||
` + r.App.PublicKey + `
|
||||
-----END PUBLIC KEY-----`
|
||||
encryptByte, err := rsa.Encrypt(publicKeyPEM, data)
|
||||
if err != nil {
|
||||
return nil, errorcode.AppRsaEncryptFail
|
||||
}
|
||||
encryptData = []byte(base64.StdEncoding.EncodeToString(encryptByte))
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Rsa) Decrypt(encryptData string) (decryptData []byte, errCode int) {
|
||||
|
||||
if r.App.PrivateKey == "" {
|
||||
return nil, errorcode.AppRsaDecryptKeyNotFound
|
||||
}
|
||||
privateKeyPEM := `-----BEGIN RSA PRIVATE KEY-----
|
||||
` + r.App.PrivateKey + `
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
decryptData, err := rsa.Decrypt(privateKeyPEM, encryptData)
|
||||
if err != nil || decryptData == nil {
|
||||
return nil, errorcode.AppRsaDecryptFail
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package apicrypt
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/utils/encrypt/sm2"
|
||||
)
|
||||
|
||||
func NewSm2(app *appmodel.App) ApiCrypt {
|
||||
return &SM2{
|
||||
App: app,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SM2) Encrypt(data string) (encryptData []byte, errCode int) {
|
||||
|
||||
if r.App.MerchantPublicKey == "" {
|
||||
return nil, errorcode.AppSM2EncryptKeyNotFound
|
||||
}
|
||||
|
||||
encryptDataString, err := sm2.SM2Encrypt(data, r.App.MerchantPublicKey)
|
||||
if err != nil {
|
||||
return nil, errorcode.AppSM2EncryptFail
|
||||
}
|
||||
encryptData = []byte(encryptDataString)
|
||||
return
|
||||
}
|
||||
|
||||
func (r *SM2) Decrypt(encryptData string) (decryptData []byte, errCode int) {
|
||||
if r.App.PrivateKey == "" || r.App.PublicKey == "" {
|
||||
return nil, errorcode.AppSM2DecryptKeyNotFound
|
||||
}
|
||||
|
||||
decryptDataString, err := sm2.SM2Decrypt(encryptData, r.App.PublicKey, r.App.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, errorcode.AppSM2DecryptFail
|
||||
}
|
||||
decryptData = []byte(decryptDataString)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package apicrypt
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/utils/encrypt/sm4"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func NewSm4(app *appmodel.App) ApiCrypt {
|
||||
return &SM4{
|
||||
App: app,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SM4) Encrypt(data string) (encryptData []byte, errCode int) {
|
||||
if r.App.MerchantPublicKey == "" || r.App.PrivateKey == "" {
|
||||
return nil, errorcode.AppSM4DecryptKeyNotFound
|
||||
}
|
||||
encryptDataString, err := sm4.Sm4Encrypt(strconv.FormatInt(r.App.Id, 10), r.App.PrivateKey, r.App.MerchantPublicKey, data, "", true)
|
||||
if err != nil {
|
||||
return nil, errorcode.AppSM4EncryptFail
|
||||
}
|
||||
encryptData = []byte(encryptDataString)
|
||||
return
|
||||
}
|
||||
|
||||
func (r *SM4) Decrypt(encryptData string) (decryptData []byte, errCode int) {
|
||||
if r.App.PrivateKey == "" || r.App.MerchantPublicKey == "" {
|
||||
return nil, errorcode.AppSM4DecryptKeyNotFound
|
||||
}
|
||||
|
||||
decryptDataString, err := sm4.Sm4Decrypt(strconv.FormatInt(r.App.Id, 10), r.App.PrivateKey, r.App.MerchantPublicKey, encryptData, true)
|
||||
if err != nil {
|
||||
return nil, errorcode.AppSM4DecryptFail
|
||||
}
|
||||
decryptData = []byte(decryptDataString)
|
||||
return
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package apicrypt
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/pojo"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
)
|
||||
|
||||
type (
|
||||
ApiCrypt interface {
|
||||
Encrypt(data string) (encryptData []byte, errCode int)
|
||||
Decrypt(encryptData string) (decryptData []byte, errCode int)
|
||||
}
|
||||
|
||||
Rsa struct {
|
||||
App *appmodel.App
|
||||
}
|
||||
|
||||
SM2 struct {
|
||||
App *appmodel.App
|
||||
}
|
||||
|
||||
SM4 struct {
|
||||
App *appmodel.App
|
||||
}
|
||||
)
|
||||
|
||||
var ApiCryptMap = map[int32]func(app *appmodel.App) ApiCrypt{
|
||||
pojo.RSA: NewRsa,
|
||||
pojo.SM2: NewSm2,
|
||||
pojo.SM4: NewSm4,
|
||||
}
|
||||
|
||||
const CryptNotError = 0
|
|
@ -0,0 +1,131 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/data"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"database/sql"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func AppList(req backend.AppListRequest) (result []appmodel.App, total int64, code int) {
|
||||
repo := data.NewAppRepo(paychannelmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
if req.MerchantId > 0 {
|
||||
conn = conn.And(builder.Eq{"merchant_id": req.MerchantId})
|
||||
}
|
||||
if req.Id > 0 {
|
||||
conn = conn.And(builder.Eq{"id": req.Id})
|
||||
}
|
||||
|
||||
// 调用repo
|
||||
appList := make([]appmodel.App, 0)
|
||||
count, err := repo.AppList(conn, req.PageRequest, &appList)
|
||||
code = handErr(err)
|
||||
return appList, count, code
|
||||
}
|
||||
|
||||
func AppCreate(app *appmodel.App) (code int) {
|
||||
db := paychannelmodel.GetInstance().GetDb()
|
||||
repo := data.NewAppRepo(db)
|
||||
merchantRepo := data.NewMerchantRepo(db)
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"id": app.MerchantId})
|
||||
merchant := merchantmodel.Merchant{}
|
||||
has, err := merchantRepo.MerchantDetail(&merchant, conn)
|
||||
if err != nil {
|
||||
return handErr(err)
|
||||
}
|
||||
if !has {
|
||||
return errorcode.MerchantNotFound
|
||||
}
|
||||
|
||||
_, err = repo.AppInsertOne(app)
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func AppUpdate(app *appmodel.App) (code int) {
|
||||
var err error
|
||||
db := paychannelmodel.GetInstance().GetDb()
|
||||
repo := data.NewAppRepo(db)
|
||||
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"Id": app.Id})
|
||||
if app.AppName != "" {
|
||||
// 编辑页面更新,备注和白名单IP可更新为空
|
||||
_, err = repo.AppUpdate(app, conn, "app_remark", "white_ip", "notify_url")
|
||||
} else {
|
||||
_, err = repo.AppUpdate(app, conn)
|
||||
}
|
||||
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func AppDelete(req entities.IdRequest) (code int) {
|
||||
repo := data.NewAppRepo(paychannelmodel.GetInstance().GetDb())
|
||||
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"Id": req.Id})
|
||||
m := appmodel.App{Id: req.Id}
|
||||
_, err := repo.AppDelete(&m, conn)
|
||||
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func AppFindOne(req entities.IdRequest, col ...string) (row *appmodel.App, code int) {
|
||||
repo := data.NewAppRepo(paychannelmodel.GetInstance().GetDb())
|
||||
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"Id": req.Id})
|
||||
m := appmodel.App{Id: req.Id}
|
||||
row, err := repo.AppFindOne(&m, conn, col...)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errorcode.AppNotFound
|
||||
}
|
||||
return row, errorcode.SystemError
|
||||
}
|
||||
return row, errorcode.Success
|
||||
}
|
||||
|
||||
func CheckApp(appCheckIn *AppCheck) {
|
||||
errCode := errorcode.Success
|
||||
appCheckIn.App, errCode = AppFindOne(entities.IdRequest{Id: appCheckIn.AppId})
|
||||
if errCode != errorcode.Success {
|
||||
appCheckIn.Code = errCode
|
||||
return
|
||||
}
|
||||
//检查app可用性
|
||||
appCheckIn.Check()
|
||||
if appCheckIn.GetCode() != errorcode.Success {
|
||||
return
|
||||
}
|
||||
//检查白名单
|
||||
if appCheckIn.Ip != "" && !appCheckIn.IpCheck(appCheckIn.Ip) {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GetAppCheck(appId int64, ip string) *AppCheck {
|
||||
appCheck := &AppCheck{
|
||||
AppId: appId,
|
||||
Ip: ip,
|
||||
Code: errorcode.Success,
|
||||
}
|
||||
CheckApp(appCheck)
|
||||
return appCheck
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/utils"
|
||||
)
|
||||
|
||||
func handErr(err error) int {
|
||||
if err != nil {
|
||||
utils.Log(nil, "sys err", err.Error())
|
||||
return errorcode.SystemError
|
||||
} else {
|
||||
return errorcode.Success
|
||||
}
|
||||
}
|
||||
|
||||
func EnCryptData(app *appmodel.App) {
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/data"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
"database/sql"
|
||||
"strings"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// MerchantList 商户列表
|
||||
func MerchantList(req backend.MerchantListRequest) (result []merchantmodel.Merchant, total int64, code int) {
|
||||
repo := data.NewMerchantRepo(merchantmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
if req.Name != "" {
|
||||
conn = conn.And(builder.Like{"name", req.Name})
|
||||
}
|
||||
if req.Contact != "" {
|
||||
conn = conn.And(builder.Like{"contact", req.Contact})
|
||||
}
|
||||
if req.Phone != "" {
|
||||
conn = conn.And(builder.Like{"phone", req.Phone})
|
||||
}
|
||||
if req.GroupInfo != "" {
|
||||
conn = conn.And(builder.In("creator", strings.Split(req.GroupInfo, ",")))
|
||||
}
|
||||
|
||||
// 调用repo
|
||||
merchantList := make([]merchantmodel.Merchant, 0)
|
||||
count, err := repo.MerchantList(conn, req.PageRequest, &merchantList)
|
||||
code = handErr(err)
|
||||
return merchantList, count, code
|
||||
}
|
||||
|
||||
func MerchantCreate(merchant *merchantmodel.Merchant) (code int) {
|
||||
repo := data.NewMerchantRepo(merchantmodel.GetInstance().GetDb())
|
||||
_, err := repo.MerchantInsertOne(merchant)
|
||||
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func MerchantUpdate(merchant *merchantmodel.Merchant) (code int) {
|
||||
repo := data.NewMerchantRepo(merchantmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"Id": merchant.Id})
|
||||
_, err := repo.MerchantUpdate(merchant, conn, "remark")
|
||||
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func MerchantDelete(req entities.IdRequest) (code int) {
|
||||
repo := data.NewMerchantRepo(merchantmodel.GetInstance().GetDb())
|
||||
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"Id": req.Id})
|
||||
m := merchantmodel.Merchant{Id: req.Id}
|
||||
_, err := repo.MerchantDelete(&m, conn)
|
||||
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func MerchantFindOne(merchant *merchantmodel.Merchant, conn builder.Cond, col ...string) (merchantInfo *merchantmodel.Merchant, code int) {
|
||||
repo := data.NewMerchantRepo(merchantmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
merchantInfo, err := repo.MerchantFindOne(merchant, conn, col...)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errorcode.MerchantNotFound
|
||||
}
|
||||
return nil, errorcode.SystemError
|
||||
}
|
||||
return merchantInfo, errorcode.Success
|
||||
}
|
||||
|
||||
func GetAndCheckMerchant(merchant *merchantmodel.Merchant, conn builder.Cond, col ...string) (merchantInfo *merchantmodel.Merchant, code int) {
|
||||
merchantInfo, code = MerchantFindOne(merchant, conn, col...)
|
||||
if code != errorcode.Success {
|
||||
return nil, code
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/data"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/ordercallbacklogmodel"
|
||||
"PaymentCenter/app/models/orderrequestlogmodel"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/models/orderthirdpaylogmodel"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"database/sql"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// 订单列表,后台查询
|
||||
func OrderList(req backend.OrderList) (result []ordersmodel.OrdersBackendList, total int64, code int) {
|
||||
repo := data.NewOrderRepo(paychannelmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
if req.Id > 0 {
|
||||
conn = conn.And(builder.Eq{"orders.id": req.Id})
|
||||
}
|
||||
if req.MerchantId > 0 {
|
||||
conn = conn.And(builder.Eq{"orders.merchant_id": req.MerchantId})
|
||||
}
|
||||
if req.PayChannelId > 0 {
|
||||
conn = conn.And(builder.Eq{"orders.pay_channel_id": req.PayChannelId})
|
||||
}
|
||||
if req.AppId > 0 {
|
||||
conn = conn.And(builder.Eq{"orders.app_id": req.AppId})
|
||||
}
|
||||
if req.OutTradeNo != "" {
|
||||
conn = conn.And(builder.Like{"orders.out_trade_no", req.OutTradeNo})
|
||||
}
|
||||
if req.Status > 0 {
|
||||
conn = conn.And(builder.Eq{"orders.status": req.Status})
|
||||
}
|
||||
if req.OrderType > 0 {
|
||||
conn = conn.And(builder.Eq{"orders.order_type": req.OrderType})
|
||||
}
|
||||
if !req.StartTime.IsZero() {
|
||||
conn = conn.And(builder.Gte{"orders.create_time": req.StartTime})
|
||||
}
|
||||
if !req.EndTime.IsZero() {
|
||||
conn = conn.And(builder.Lte{"orders.create_time": req.EndTime})
|
||||
}
|
||||
|
||||
// 调用repo
|
||||
orderList := make([]ordersmodel.OrdersBackendList, 0)
|
||||
count, err := repo.OrdersBackendList(conn, req.PageRequest, &orderList)
|
||||
code = handErr(err)
|
||||
return orderList, count, code
|
||||
}
|
||||
|
||||
// 请求日志列表
|
||||
func OrderRequestLogsList(req backend.OrderLogsListRequest) (requestLog []orderrequestlogmodel.OrderRequestLog, total int64, code int) {
|
||||
requestRepo := data.NewOrderRequestLogRepo(paychannelmodel.GetInstance().GetDb())
|
||||
conn := builder.NewCond()
|
||||
if req.OrderId > 0 {
|
||||
conn = conn.And(builder.Eq{"orders.id": req.OrderId})
|
||||
}
|
||||
if req.Id > 0 {
|
||||
conn = conn.And(builder.Eq{"order_request_log.id": req.Id})
|
||||
}
|
||||
if req.AppId > 0 {
|
||||
conn = conn.And(builder.Eq{"order_request_log.app_id": req.AppId})
|
||||
}
|
||||
if req.OutTradeNo != "" {
|
||||
conn = conn.And(builder.Like{"order_request_log.out_trade_no", req.OutTradeNo})
|
||||
}
|
||||
// 请求日志
|
||||
orderLogList := make([]orderrequestlogmodel.OrderRequestLog, 0)
|
||||
total, err := requestRepo.OrderRequestLogBackendList(conn, req.PageRequest, &orderLogList)
|
||||
code = handErr(err)
|
||||
return orderLogList, total, code
|
||||
}
|
||||
|
||||
// 回调日志列表
|
||||
func OrderCallbackLogsList(req backend.OrderLogsListRequest) (callback []ordercallbacklogmodel.OrderCallbackLog, total int64, code int) {
|
||||
callbackRepo := data.NewOrderCallbackLogRepo(paychannelmodel.GetInstance().GetDb())
|
||||
conn := builder.NewCond()
|
||||
if req.OrderId > 0 {
|
||||
conn = conn.And(builder.Eq{"order_id": req.OrderId})
|
||||
}
|
||||
if req.Id > 0 {
|
||||
conn = conn.And(builder.Eq{"id": req.Id})
|
||||
}
|
||||
// 回调日志
|
||||
callbackLogList := make([]ordercallbacklogmodel.OrderCallbackLog, 0)
|
||||
total, err := callbackRepo.OrderCallbackLogList(conn, req.PageRequest, &callbackLogList)
|
||||
code = handErr(err)
|
||||
|
||||
return callbackLogList, total, code
|
||||
}
|
||||
|
||||
// 三方日志列表
|
||||
func OrderThirdLogsList(req backend.OrderLogsListRequest) (thirdLod []orderthirdpaylogmodel.OrderThirdPayLog, total int64, code int) {
|
||||
thirdRepo := data.NewOrderThirdPayLogRepo(paychannelmodel.GetInstance().GetDb())
|
||||
// 三方日志
|
||||
conn := builder.NewCond()
|
||||
if req.OrderId > 0 {
|
||||
conn = conn.And(builder.Eq{"order_id": req.OrderId})
|
||||
}
|
||||
if req.Id > 0 {
|
||||
conn = conn.And(builder.Eq{"id": req.Id})
|
||||
}
|
||||
thirdLogList := make([]orderthirdpaylogmodel.OrderThirdPayLog, 0)
|
||||
total, err := thirdRepo.OrderThirdPayLogList(conn, req.PageRequest, &thirdLogList)
|
||||
code = handErr(err)
|
||||
return thirdLogList, total, code
|
||||
}
|
||||
|
||||
func OrderCreate(orderIn *ordersmodel.Orders) (orderOut *ordersmodel.Orders, code int) {
|
||||
repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb())
|
||||
_, err := repo.OrderInsertOne(orderIn)
|
||||
code = handErr(err)
|
||||
return orderIn, code
|
||||
}
|
||||
|
||||
func OrderUpdate(order *ordersmodel.Orders, col ...string) (code int) {
|
||||
repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"Id": order.Id})
|
||||
_, err := repo.OrderUpdate(order, conn, col...)
|
||||
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func OrderFindOne(order *ordersmodel.Orders, conn builder.Cond, col ...string) (merchantInfo *ordersmodel.Orders, code int) {
|
||||
repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
orderInfo, err := repo.OrderFindOne(order, conn, col...)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errorcode.OrdersNotFound
|
||||
}
|
||||
return nil, errorcode.SystemError
|
||||
}
|
||||
return orderInfo, errorcode.Success
|
||||
}
|
||||
|
||||
func PayOrderCheckRepeat(order *ordersmodel.Orders, conn builder.Cond) (exist bool, code int) {
|
||||
_, code = OrderFindOne(order, conn)
|
||||
if code != errorcode.OrdersNotFound {
|
||||
return false, errorcode.Success
|
||||
}
|
||||
return true, code
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/data"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/http/entities/backend"
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"database/sql"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func PayChannelList(req backend.PayChannelListRequest) (result []paychannelmodel.PayChannel, total int64, code int) {
|
||||
repo := data.NewPayChannelRepo(paychannelmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
if req.MerchantId > 0 {
|
||||
conn = conn.And(builder.Eq{"merchant_id": req.MerchantId})
|
||||
}
|
||||
if req.Id > 0 {
|
||||
conn = conn.And(builder.Eq{"id": req.Id})
|
||||
}
|
||||
|
||||
// 调用repo
|
||||
paychannelList := make([]paychannelmodel.PayChannel, 0)
|
||||
count, err := repo.PayChannelList(conn, req.PageRequest, &paychannelList)
|
||||
code = handErr(err)
|
||||
return paychannelList, count, code
|
||||
}
|
||||
|
||||
func PayChannelCreate(payChannel *paychannelmodel.PayChannel) (code int) {
|
||||
db := paychannelmodel.GetInstance().GetDb()
|
||||
repo := data.NewPayChannelRepo(db)
|
||||
merchantRepo := data.NewMerchantRepo(db)
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"id": payChannel.MerchantId})
|
||||
merchant := merchantmodel.Merchant{}
|
||||
has, err := merchantRepo.MerchantDetail(&merchant, conn)
|
||||
if err != nil {
|
||||
return handErr(err)
|
||||
}
|
||||
if !has {
|
||||
return errorcode.MerchantNotFound
|
||||
}
|
||||
|
||||
_, err = repo.PayChannelInsertOne(payChannel)
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func PayChannelUpdate(payChannel *paychannelmodel.PayChannel) (code int) {
|
||||
db := paychannelmodel.GetInstance().GetDb()
|
||||
repo := data.NewPayChannelRepo(db)
|
||||
|
||||
// 拼接查询条件
|
||||
uconn := builder.NewCond()
|
||||
uconn = uconn.And(builder.Eq{"Id": payChannel.Id})
|
||||
_, err := repo.PayChannelUpdate(payChannel, uconn, "white_ip")
|
||||
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func PayChannelDelete(req entities.IdRequest) (code int) {
|
||||
repo := data.NewPayChannelRepo(paychannelmodel.GetInstance().GetDb())
|
||||
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"Id": req.Id})
|
||||
m := paychannelmodel.PayChannel{Id: req.Id}
|
||||
_, err := repo.PayChannelDelete(&m, conn)
|
||||
|
||||
code = handErr(err)
|
||||
return
|
||||
}
|
||||
|
||||
func PayChannelGet(payChannel *paychannelmodel.PayChannel) (code int) {
|
||||
repo := data.NewPayChannelRepo(paychannelmodel.GetInstance().GetDb())
|
||||
|
||||
// 拼接查询条件
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"id": payChannel.Id})
|
||||
has, err := repo.PayChannelGet(payChannel, conn)
|
||||
if err != nil {
|
||||
return handErr(err)
|
||||
}
|
||||
if !has {
|
||||
return errorcode.PayChannelNotFound
|
||||
}
|
||||
|
||||
code = errorcode.Success
|
||||
return
|
||||
}
|
||||
|
||||
func PayChannelFindOne(channel *paychannelmodel.PayChannel, conn builder.Cond, col ...string) (merchantInfo *paychannelmodel.PayChannel, code int) {
|
||||
repo := data.NewPayChannelRepo(paychannelmodel.GetInstance().GetDb())
|
||||
// 拼接查询条件
|
||||
channelInfo, err := repo.PayChannelFindOne(channel, conn, col...)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errorcode.PayChannelNotFound
|
||||
}
|
||||
return nil, errorcode.SystemError
|
||||
}
|
||||
return channelInfo, errorcode.Success
|
||||
}
|
||||
|
||||
func GetAndCheckPayChannel(channel *paychannelmodel.PayChannel, conn builder.Cond, col ...string) (channelInfo *paychannelmodel.PayChannel, code int) {
|
||||
channelInfo, code = PayChannelFindOne(channel, conn, col...)
|
||||
if code != errorcode.Success {
|
||||
return nil, code
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/data"
|
||||
"PaymentCenter/app/models/orderrequestlogmodel"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func RequestLogCreate(log *orderrequestlogmodel.OrderRequestLog) (*orderrequestlogmodel.OrderRequestLog, int) {
|
||||
db := orderrequestlogmodel.GetInstance().GetDb()
|
||||
repo := data.NewOrderRequestLogRepo(db)
|
||||
id, err := repo.OrderRequestLogInsertOne(log)
|
||||
code := handErr(err)
|
||||
if err != nil {
|
||||
log.Id = id
|
||||
}
|
||||
return log, code
|
||||
}
|
||||
|
||||
func RequestLogUpdate(log *orderrequestlogmodel.OrderRequestLog) (logOut *orderrequestlogmodel.OrderRequestLog, code int) {
|
||||
db := orderrequestlogmodel.GetInstance().GetDb()
|
||||
repo := data.NewOrderRequestLogRepo(db)
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"Id": log.Id})
|
||||
id, err := repo.OrderRequestLogUpdate(log, conn)
|
||||
code = handErr(err)
|
||||
if err != nil {
|
||||
log.Id = id
|
||||
}
|
||||
return log, code
|
||||
}
|
||||
|
||||
func AddRequestLog(requestDataByte []byte, ip string, url string) (int64, int) {
|
||||
requestLog, checkCode := RequestLogCreate(&orderrequestlogmodel.OrderRequestLog{
|
||||
IpAddress: ip,
|
||||
MerchantRequest: string(requestDataByte),
|
||||
URL: url,
|
||||
MerchantResponse: "{}",
|
||||
Status: common.STATUS_ENABLE,
|
||||
})
|
||||
return requestLog.Id, checkCode
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package api
|
||||
|
||||
type OrdersResp struct {
|
||||
OrderNo int64 `json:"order_no"`
|
||||
OrderType int `json:"order_type"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
Amount int `json:"amount"`
|
||||
PayerTotal int `json:"payer_total"`
|
||||
Desc string `json:"desc"`
|
||||
|
||||
Status int `json:"status"`
|
||||
CreateTime string `json:"create_time"`
|
||||
}
|
||||
|
||||
type OrdersWithUrl struct {
|
||||
Order *OrdersResp
|
||||
Url string
|
||||
}
|
||||
|
||||
func (o *OrdersResp) WithUrl(url string) *OrdersWithUrl {
|
||||
return &OrdersWithUrl{
|
||||
Order: o,
|
||||
Url: url,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OrdersResp) WithAes(url string) *OrdersWithUrl {
|
||||
return &OrdersWithUrl{
|
||||
Order: o,
|
||||
Url: url,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/apicrypt"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func EnCrypt(app *appmodel.App, data interface{}) ([]byte, int) {
|
||||
appCheck := services.NewAppCheck(app)
|
||||
cryptFunc := appCheck.Crypt()
|
||||
if cryptFunc == nil {
|
||||
return nil, appCheck.Code
|
||||
}
|
||||
dataByte, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, errorcode.AppAesEncryptFail
|
||||
}
|
||||
|
||||
encryptData, errCode := cryptFunc(appCheck.App).Encrypt(string(dataByte))
|
||||
if errCode != apicrypt.CryptNotError {
|
||||
return nil, errCode
|
||||
}
|
||||
return encryptData, errorcode.Success
|
||||
}
|
||||
|
||||
func DeCrypt(app *appmodel.App, data string, aesKey string) ([]byte, int) {
|
||||
appCheck := services.NewAppCheck(app)
|
||||
cryptFunc := appCheck.Crypt()
|
||||
if cryptFunc == nil {
|
||||
return nil, appCheck.Code
|
||||
}
|
||||
dataByte, errCode := cryptFunc(app).Decrypt(data)
|
||||
if errCode != apicrypt.CryptNotError {
|
||||
return nil, errCode
|
||||
}
|
||||
if len(dataByte) == 0 {
|
||||
return nil, errorcode.AppDeEncryptFail
|
||||
}
|
||||
|
||||
return dataByte, errorcode.Success
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
package do
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
"context"
|
||||
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/third/paymentService"
|
||||
)
|
||||
|
||||
type PayParam struct {
|
||||
Merchant *merchantmodel.Merchant
|
||||
Channel *paychannelmodel.PayChannel
|
||||
App_id int64
|
||||
OutTradeNo string
|
||||
Amount int
|
||||
ExtJson string
|
||||
Desc string
|
||||
ClientIp string
|
||||
}
|
||||
|
||||
type Pay struct {
|
||||
ctx *context.Context
|
||||
PayParam *PayParam
|
||||
RelationOrder *ordersmodel.Orders
|
||||
Order *ordersmodel.Orders
|
||||
PayCode int
|
||||
Url string
|
||||
}
|
||||
|
||||
func NewPayWithPayCheck(paycheck *PayCheck) *Pay {
|
||||
return &Pay{
|
||||
ctx: paycheck.ctx,
|
||||
PayParam: &PayParam{
|
||||
Merchant: paycheck.Merchant,
|
||||
Channel: paycheck.Channel,
|
||||
App_id: paycheck.Reqs.AppId,
|
||||
OutTradeNo: paycheck.Reqs.OutTradeNo,
|
||||
Amount: paycheck.Reqs.Amount,
|
||||
ExtJson: paycheck.Reqs.ExtJson,
|
||||
Desc: paycheck.Reqs.Desc,
|
||||
ClientIp: paycheck.AppCheck.Ip,
|
||||
},
|
||||
RelationOrder: paycheck.OldOrder,
|
||||
PayCode: errorcode.Success,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Pay) CreateOrder(order_type int) {
|
||||
if _, ok := common.OrderTypeList[order_type]; !ok { //判断是否是支持的支付渠道
|
||||
w.PayCode = errorcode.PayChannelNotFound
|
||||
return
|
||||
}
|
||||
order := &ordersmodel.Orders{
|
||||
MerchantId: w.PayParam.Merchant.Id,
|
||||
PayChannelId: w.PayParam.Channel.Id,
|
||||
AppId: w.PayParam.App_id,
|
||||
OutTradeNo: w.PayParam.OutTradeNo,
|
||||
OrderType: order_type,
|
||||
Amount: w.PayParam.Amount,
|
||||
ExtJson: w.PayParam.ExtJson,
|
||||
Desc: w.PayParam.Desc,
|
||||
Status: common.ORDER_STATUS_WAITPAY,
|
||||
}
|
||||
if order_type == common.ORDER_TYPE_REFUND {
|
||||
order.RefundOrderId = w.RelationOrder.Id
|
||||
}
|
||||
w.Order, w.PayCode = services.OrderCreate(order)
|
||||
}
|
||||
|
||||
func (w *Pay) PayUrl() (url string) {
|
||||
var (
|
||||
payFunc func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error
|
||||
ok bool
|
||||
)
|
||||
thirdPay := &paymentService.PayOrderRequest{
|
||||
PayChannelId: w.PayParam.Channel.Id,
|
||||
OrderId: w.Order.Id,
|
||||
ChannelType: w.PayParam.Channel.ChannelType,
|
||||
Description: w.Order.Desc,
|
||||
Amount: w.Order.Amount,
|
||||
PayerClientIp: w.PayParam.ClientIp,
|
||||
}
|
||||
if payFunc, ok = PayWayList[w.PayParam.Channel.ChannelType]; !ok {
|
||||
w.PayCode = errorcode.PayChannelNotBuild
|
||||
return
|
||||
}
|
||||
err := payFunc(thirdPay, w.PayParam.Channel)
|
||||
if err != nil {
|
||||
w.PayCode = errorcode.PayChannelExtJsonError
|
||||
return
|
||||
}
|
||||
res := paymentService.PaymentService(*w.ctx, *thirdPay)
|
||||
|
||||
if res.Code == payCommon.PAY_SUCCESS_CODE {
|
||||
w.Order.Status = common.ORDER_STATUS_PAYING
|
||||
code := services.OrderUpdate(w.Order, "status")
|
||||
if code != errorcode.Success {
|
||||
w.PayCode = code
|
||||
}
|
||||
w.Url = res.Result
|
||||
} else {
|
||||
w.PayCode = errorcode.PrePayFail
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Pay) Refund() {
|
||||
var (
|
||||
refundFunc func(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error
|
||||
ok bool
|
||||
)
|
||||
thirdPayRefund := &paymentService.OrderRefundRequest{
|
||||
OrderId: w.Order.Id,
|
||||
RefundOrderId: w.RelationOrder.Id,
|
||||
RefundReason: w.PayParam.Desc,
|
||||
RefundAmount: int64(w.PayParam.Amount),
|
||||
}
|
||||
if refundFunc, ok = RefundWayList[w.PayParam.Channel.ChannelType]; !ok {
|
||||
w.PayCode = errorcode.PayChannelNotBuild
|
||||
return
|
||||
}
|
||||
err := refundFunc(thirdPayRefund, w.PayParam.Channel)
|
||||
if err != nil {
|
||||
w.PayCode = errorcode.PayChannelExtJsonError
|
||||
return
|
||||
}
|
||||
res := paymentService.OrderRefund(*w.ctx, *thirdPayRefund)
|
||||
if res.Code == payCommon.PAY_SUCCESS_CODE {
|
||||
w.Order.Status = common.ORDER_STATUS_PAYING
|
||||
code := services.OrderUpdate(w.Order, "status")
|
||||
if code != errorcode.Success {
|
||||
w.PayCode = code
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w.PayCode = errorcode.PreRefundFail
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package do
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay/types"
|
||||
"xorm.io/builder"
|
||||
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
"PaymentCenter/app/models/orderrequestlogmodel"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"context"
|
||||
)
|
||||
|
||||
type PayCheck struct {
|
||||
ctx *context.Context
|
||||
Reqs *types.Reqs
|
||||
AppCheck *services.AppCheck
|
||||
RequestLog *orderrequestlogmodel.OrderRequestLog
|
||||
Channel *paychannelmodel.PayChannel
|
||||
Merchant *merchantmodel.Merchant
|
||||
OldOrder *ordersmodel.Orders
|
||||
CheckCode int
|
||||
}
|
||||
|
||||
func NewPayCheck(ctx *context.Context, reqs *types.Reqs, appCheck *services.AppCheck, ip string) *PayCheck {
|
||||
if appCheck == nil {
|
||||
appCheck = services.GetAppCheck(reqs.AppId, ip)
|
||||
}
|
||||
return &PayCheck{
|
||||
ctx: ctx,
|
||||
Reqs: reqs,
|
||||
AppCheck: appCheck,
|
||||
CheckCode: appCheck.Code,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *PayCheck) CheckPayInfo() {
|
||||
w.CheckMerchant()
|
||||
if w.CheckCode != errorcode.Success {
|
||||
return
|
||||
}
|
||||
w.CheckPayChannel()
|
||||
if w.CheckCode != errorcode.Success {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (w *PayCheck) CheckPayChannel() {
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"id": w.Reqs.PayChannelId})
|
||||
w.Channel, w.CheckCode = services.GetAndCheckPayChannel(&paychannelmodel.PayChannel{}, conn)
|
||||
}
|
||||
|
||||
func (w *PayCheck) CheckMerchant() {
|
||||
conn := builder.NewCond()
|
||||
conn = conn.And(builder.Eq{"id": w.AppCheck.App.MerchantId})
|
||||
w.Merchant, w.CheckCode = services.GetAndCheckMerchant(&merchantmodel.Merchant{}, conn)
|
||||
}
|
||||
|
||||
func (w *PayCheck) CheckOrderPay() {
|
||||
w.GetOrder(&types.OrderFindOne{
|
||||
OutTradeNo: w.Reqs.OutTradeNo,
|
||||
})
|
||||
if w.OldOrder != nil {
|
||||
switch w.OldOrder.Status {
|
||||
case common.ORDER_STATUS_CLOSE:
|
||||
w.CheckCode = errorcode.OrderClosed
|
||||
case common.ORDER_STATUS_FAILED:
|
||||
w.CheckCode = errorcode.OrderFailed
|
||||
case common.ORDER_STATUS_PAYED:
|
||||
w.CheckCode = errorcode.OrderPayed
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (w *PayCheck) CheckOrderRefund() {
|
||||
w.GetOrder(&types.OrderFindOne{
|
||||
OutTradeNo: w.Reqs.RefundOutTradeNo,
|
||||
OrderId: w.Reqs.RefundOrderId,
|
||||
})
|
||||
if w.OldOrder == nil {
|
||||
w.CheckCode = errorcode.RefundOrderNotFound
|
||||
return
|
||||
}
|
||||
if w.OldOrder.Status != common.ORDER_STATUS_PAYED {
|
||||
w.CheckCode = errorcode.OrderStatusRefundNotSupport
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *PayCheck) GetOrder(orderCol *types.OrderFindOne) {
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"app_id": w.AppCheck.AppId})
|
||||
if orderCol.OrderId == "" && orderCol.OutTradeNo == "" {
|
||||
w.CheckCode = errorcode.OrdersNotFound
|
||||
return
|
||||
}
|
||||
if orderCol.OrderId != "" {
|
||||
cond = cond.And(builder.Eq{"order_id": orderCol.OrderId})
|
||||
}
|
||||
if orderCol.OutTradeNo != "" {
|
||||
cond = cond.And(builder.Eq{"out_trade_no": orderCol.OutTradeNo})
|
||||
}
|
||||
order, code := services.OrderFindOne(&ordersmodel.Orders{}, cond)
|
||||
if code == errorcode.SystemError {
|
||||
w.CheckCode = code
|
||||
return
|
||||
}
|
||||
if code == errorcode.Success {
|
||||
w.OldOrder = order
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package do
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/third/paymentService"
|
||||
"github.com/bytedance/sonic"
|
||||
)
|
||||
|
||||
var PayWayList = map[int]func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error{
|
||||
common.PAY_CHANNEL_WECHAT_H5: WechatH5,
|
||||
common.PAY_CHANNEL_ALIPAY_WEB: AlipayWeb,
|
||||
}
|
||||
|
||||
func WechatH5(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error {
|
||||
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonPayInfo.Wx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonPayInfo.Wx.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
||||
func AlipayWeb(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error {
|
||||
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonPayInfo.Ali)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonPayInfo.Ali.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package do
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/third/paymentService"
|
||||
"github.com/bytedance/sonic"
|
||||
)
|
||||
|
||||
var RefundWayList = map[int]func(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error{
|
||||
common.PAY_CHANNEL_WECHAT_H5: WechatH5Refund,
|
||||
common.PAY_CHANNEL_ALIPAY_WEB: AlipayWebRefund,
|
||||
}
|
||||
|
||||
func WechatH5Refund(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error {
|
||||
commonRefundInfo.PayChannel = common.PAY_CHANNLE_TYPE_WECHAT
|
||||
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonRefundInfo.Wx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonRefundInfo.Wx.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
||||
func AlipayWebRefund(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error {
|
||||
commonRefundInfo.PayChannel = common.PAY_CHANNLE_TYPE_ZFB
|
||||
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonRefundInfo.Ali)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonRefundInfo.Ali.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package thirdpay
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/http/entities/front"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay/api"
|
||||
thirdpay "PaymentCenter/app/services/thirdpay/do"
|
||||
"PaymentCenter/app/services/thirdpay/types"
|
||||
"context"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
func ThirdPayUrl(check *thirdpay.PayCheck) *thirdpay.Pay {
|
||||
pay := ThirdPay(check)
|
||||
// 支付
|
||||
pay.PayUrl()
|
||||
return pay
|
||||
}
|
||||
|
||||
func NewOrdersResp(db *ordersmodel.Orders) *api.OrdersResp {
|
||||
return &api.OrdersResp{
|
||||
OrderNo: db.Id,
|
||||
OutTradeNo: db.OutTradeNo,
|
||||
Status: db.Status,
|
||||
OrderType: db.OrderType,
|
||||
Amount: db.Amount,
|
||||
PayerTotal: db.PayerTotal,
|
||||
Desc: db.Desc,
|
||||
CreateTime: db.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
}
|
||||
|
||||
func ThirdPayInfoCheck(ctx context.Context, payReq *front.PayReqs, appCheck *services.AppCheck, ip string) (check *thirdpay.PayCheck) {
|
||||
var req types.Reqs
|
||||
copier.Copy(&req, payReq)
|
||||
check = thirdpay.NewPayCheck(&ctx, &req, appCheck, ip)
|
||||
// 校验表单
|
||||
check.CheckPayInfo()
|
||||
if check.CheckCode != errorcode.Success {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ThirdPayRefund(ctx context.Context, refundReq *front.RefundReqs, appCheck *services.AppCheck, ip string) (refund *thirdpay.Pay) {
|
||||
var req types.Reqs
|
||||
copier.Copy(&req, refundReq)
|
||||
check := thirdpay.NewPayCheck(&ctx, &req, appCheck, ip)
|
||||
// 校验表单
|
||||
check.CheckPayInfo()
|
||||
if check.CheckCode != errorcode.Success {
|
||||
return
|
||||
}
|
||||
check.CheckOrderRefund()
|
||||
if check.CheckCode != errorcode.Success {
|
||||
return
|
||||
}
|
||||
refund = thirdpay.NewPayWithPayCheck(check)
|
||||
refund.CreateOrder(common.ORDER_TYPE_REFUND)
|
||||
refund.Refund()
|
||||
return
|
||||
}
|
||||
|
||||
func ThirdPay(check *thirdpay.PayCheck) (pay *thirdpay.Pay) {
|
||||
pay = thirdpay.NewPayWithPayCheck(check)
|
||||
// 创建订单
|
||||
if check.OldOrder != nil {
|
||||
pay.Order = check.OldOrder
|
||||
} else {
|
||||
pay.CreateOrder(common.ORDER_TYPE_PAY)
|
||||
if pay.PayCode != errorcode.Success {
|
||||
return pay
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package thirdpay_notify
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/data"
|
||||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/models/ordercallbacklogmodel"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/app/utils/httpclient"
|
||||
"github.com/bytedance/sonic"
|
||||
"time"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
type OrderNotify struct {
|
||||
order *ordersmodel.Orders
|
||||
Code int
|
||||
app *appmodel.App
|
||||
|
||||
OrderId int64
|
||||
Status int //订单状态
|
||||
ActualAmount int
|
||||
Msg string
|
||||
CompleteTime time.Time
|
||||
}
|
||||
|
||||
type OrderNotifyResp struct {
|
||||
OrderId int64
|
||||
Send bool
|
||||
ErrCode int
|
||||
SendTime time.Time
|
||||
Content *OrderNotify
|
||||
}
|
||||
|
||||
type OrderNotifySendContent struct {
|
||||
OrderId int64 `json:"order_id"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
CompleteTime time.Time `json:"complete_time"`
|
||||
OrderType int `json:"order-type"`
|
||||
Status int `json:"status"`
|
||||
Msg string `json:"msg"`
|
||||
ErrCode int `json:"err_code"`
|
||||
AppId int64 `json:"app_id"`
|
||||
ChannelId int64 `json:"channel_id"`
|
||||
MerchantId int64 `json:"merchant_id"`
|
||||
}
|
||||
|
||||
func NewOrderNotifyWithHandle(orderId int64, Status int, actualAmount int, msg string) *OrderNotifyResp {
|
||||
orderNotify := &OrderNotify{
|
||||
OrderId: orderId,
|
||||
Status: Status,
|
||||
ActualAmount: actualAmount,
|
||||
Msg: msg,
|
||||
Code: errorcode.Success,
|
||||
}
|
||||
return orderNotify.Handle()
|
||||
}
|
||||
|
||||
func (o *OrderNotify) NotifyRespFail(errorCode int) *OrderNotifyResp {
|
||||
return &OrderNotifyResp{
|
||||
OrderId: o.OrderId,
|
||||
Send: false,
|
||||
ErrCode: errorCode,
|
||||
Content: o,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OrderNotify) Handle() (res *OrderNotifyResp) {
|
||||
o.checkOrder()
|
||||
if o.Code != errorcode.Success {
|
||||
return o.NotifyRespFail(o.Code)
|
||||
}
|
||||
o.checkApp()
|
||||
if o.Code != errorcode.Success {
|
||||
return o.NotifyRespFail(o.Code)
|
||||
}
|
||||
o.updateOrder()
|
||||
if o.Code != errorcode.Success {
|
||||
return o.NotifyRespFail(o.Code)
|
||||
}
|
||||
o.sendNotify(o.setBody())
|
||||
if o.Code != errorcode.Success {
|
||||
return o.NotifyRespFail(o.Code)
|
||||
}
|
||||
return &OrderNotifyResp{
|
||||
OrderId: o.OrderId,
|
||||
Send: true,
|
||||
ErrCode: o.Code,
|
||||
Content: o,
|
||||
}
|
||||
}
|
||||
|
||||
// 发送下游回调通知
|
||||
func (o *OrderNotify) sendNotify(body *OrderNotifySendContent) {
|
||||
if o.app.NotifyUrl == "" {
|
||||
o.Code = errorcode.AppNotifyUrlNotFound
|
||||
return
|
||||
}
|
||||
var callbackStatus = common.STATUS_ENABLE
|
||||
var response string
|
||||
|
||||
bodyByte, _ := sonic.Marshal(&body)
|
||||
headers := make(map[string]string, 1)
|
||||
headers["Content-Type"] = "application/json"
|
||||
resByte, err := httpclient.FastHttpPost(o.app.NotifyUrl, headers, bodyByte, 0)
|
||||
if err != nil || string(resByte) != "success" {
|
||||
o.Code = errorcode.NotifySendFail
|
||||
callbackStatus = common.STATUS_DISABLED
|
||||
response = "url=" + o.app.NotifyUrl + "|error=" + err.Error()
|
||||
}
|
||||
response = string(resByte) + response
|
||||
// 记录回调日志
|
||||
go func(orderId int64, status int, request, response string) {
|
||||
repo := data.NewOrderCallbackLogRepo(ordercallbacklogmodel.GetInstance().GetDb())
|
||||
log := ordercallbacklogmodel.OrderCallbackLog{
|
||||
OrderId: orderId,
|
||||
MerchantRequest: string(bodyByte),
|
||||
Status: status,
|
||||
MerchantResponse: response,
|
||||
}
|
||||
_, insertErr := repo.OrderCallbackLogInsertOne(&log)
|
||||
if insertErr != nil {
|
||||
utils.Log(nil, "回调写入日志error", insertErr)
|
||||
}
|
||||
}(o.OrderId, callbackStatus, string(bodyByte), response)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OrderNotify) setBody() *OrderNotifySendContent {
|
||||
return &OrderNotifySendContent{
|
||||
OrderId: o.OrderId,
|
||||
OutTradeNo: o.order.OutTradeNo,
|
||||
CompleteTime: o.CompleteTime,
|
||||
Status: o.order.Status,
|
||||
OrderType: o.order.OrderType,
|
||||
Msg: o.Msg,
|
||||
ErrCode: o.Status,
|
||||
AppId: o.order.AppId,
|
||||
ChannelId: o.order.PayChannelId,
|
||||
MerchantId: o.order.MerchantId,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OrderNotify) updateOrder() {
|
||||
if _, ok := common.OrderStatusMap[o.Status]; !ok {
|
||||
o.Code = errorcode.OrderStatusErr
|
||||
return
|
||||
}
|
||||
o.order.Status = o.Status
|
||||
o.order.PayerTotal = o.ActualAmount
|
||||
o.Code = services.OrderUpdate(o.order, "status")
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OrderNotify) checkApp() {
|
||||
o.app, o.Code = services.AppFindOne(entities.IdRequest{Id: o.order.AppId})
|
||||
if o.Code != errorcode.Success {
|
||||
return
|
||||
}
|
||||
|
||||
//if o.app.NotifyUrl == "" {
|
||||
// o.Code = errorcode.AppNotifyUrlNotFound
|
||||
// return
|
||||
//}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OrderNotify) checkOrder() {
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"id": o.OrderId})
|
||||
o.order, o.Code = services.OrderFindOne(&ordersmodel.Orders{}, cond)
|
||||
if o.Code != errorcode.OrdersExist {
|
||||
return
|
||||
}
|
||||
|
||||
if o.order.Status != common.ORDER_STATUS_PAYING {
|
||||
o.Code = errorcode.OrderStatusErr
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package types
|
||||
|
||||
import "PaymentCenter/app/http/entities/front"
|
||||
|
||||
type Reqs struct {
|
||||
front.PayCommonReqBody
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
RefundOutTradeNo string `json:"refund_out_trade_no"`
|
||||
RefundOrderId string `json:"refundOrder_id"`
|
||||
}
|
||||
|
||||
type OrderFindOne struct {
|
||||
OrderId string
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
package market
|
||||
|
||||
import (
|
||||
"PaymentCenter/config"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/pkg/errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type MarketClient struct {
|
||||
cfg config.MarketConfig
|
||||
}
|
||||
|
||||
type MarketSendRequest struct {
|
||||
AppId string `json:"app_id"` //APP ID
|
||||
Sign string `json:"sign"` //签名
|
||||
ReqCode string `json:"req_code"` //固定值:voucher.create
|
||||
MemId string `json:"mem_id"` //商户号
|
||||
ReqSerialNo string `json:"req_serial_no"` //请求唯一流水号 最大32位
|
||||
TimeTamp string `json:"timestamp"` //时间戳 yyyyMMddHHmmss
|
||||
PosId string `json:"pos_id"` //商户方平台号
|
||||
VoucherId string `json:"voucher_id"` //制码批次号
|
||||
VoucherNum int `json:"voucher_num"` //请券数量,默认是 1
|
||||
MobileNo string `json:"mobile_no"` //11 手机号,可传空字符串
|
||||
SendMsg string `json:"send_msg"` //是否发送短信:2- 发送 1-不发送
|
||||
}
|
||||
|
||||
type MarketSenResponse struct {
|
||||
VoucherId string `json:"voucher_id"` //制码批次号
|
||||
VoucherCode string `json:"voucher_code"` //券码
|
||||
ShortUrl string `json:"short_url"` //含二维码、条码的短链接
|
||||
VoucherSdate string `json:"voucher_sdate"` //有效期起
|
||||
VoucherEdate string `json:"voucher_edate"` //有效期止
|
||||
CodeType string `json:"code_type"` //码类型: 00- 代金券 01- 满减券
|
||||
}
|
||||
|
||||
type MarketResponse struct {
|
||||
ErrCode string `json:"errCode"` //00-成功 其他:失败
|
||||
Msg string `json:"msg"` //描 述 (失败时必填)
|
||||
Data MarketSenResponse `json:"data"`
|
||||
}
|
||||
|
||||
func (this *MarketSendRequest) toMap() (resultMap map[string]interface{}) {
|
||||
// Marshal the struct to JSON, ignoring omitempty fields.
|
||||
jsonBytes, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Unmarshal the JSON into a map to get the final result.
|
||||
err = json.Unmarshal(jsonBytes, &resultMap)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return resultMap
|
||||
}
|
||||
|
||||
func (this *MarketClient) doPost(url string, jsonBytes []byte) (body []byte, err error) {
|
||||
// 创建POST请求
|
||||
url = this.cfg.Host + url
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置Content-Type头
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// 创建HTTP客户端
|
||||
client := &http.Client{}
|
||||
|
||||
// 发送请求并处理响应
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// 读取响应体
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = errors.New("HTTP request failed: " + resp.Status)
|
||||
return
|
||||
}
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package market
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/utils/encrypt"
|
||||
"PaymentCenter/config"
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewMarketClient(cfg config.MarketConfig) *MarketClient {
|
||||
cfg.Sign = "-----BEGIN RSA PRIVATE KEY-----\n" + cfg.Sign + "\n-----END RSA PRIVATE KEY-----"
|
||||
return &MarketClient{
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MarketSend
|
||||
券码生成接口
|
||||
- 请求地址:/openApi/v1/market/key/send
|
||||
- 说明:发券接口应支持使用同一流水号进行重复请求,即:当调用该接口失败时,可 以使用同一流水号进行再次请求,接口需要根据请求的流水号进行判断,若无该流水 号的券码信息则新生成后返回,若有该流水号的券码信息则直接返回该券码的信息
|
||||
orderNo: 订单号
|
||||
VoucherId: 制码批次号
|
||||
MobileNo: 11 手机号,可传空字符串
|
||||
SendMsg: 是否发送短信:2- 发送 1-不发送
|
||||
*/
|
||||
func (this *MarketClient) MarketSend(orderNo, VoucherId, MobileNo, SendMsg string) (res MarketResponse, err error) {
|
||||
url := "/openApi/v1/market/key/send"
|
||||
request := MarketSendRequest{
|
||||
AppId: this.cfg.AppId,
|
||||
ReqCode: this.cfg.ReqCode,
|
||||
MemId: this.cfg.MemId,
|
||||
PosId: this.cfg.PosId,
|
||||
TimeTamp: time.Now().Format("20060102150405"),
|
||||
VoucherId: VoucherId,
|
||||
ReqSerialNo: orderNo,
|
||||
VoucherNum: 1,
|
||||
MobileNo: MobileNo,
|
||||
SendMsg: SendMsg,
|
||||
}
|
||||
|
||||
request.Sign, err = MakeRsaSign(this.cfg.Sign, request.toMap())
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
data, err := this.doPost(url, bytes)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
err = json.Unmarshal(data, &res)
|
||||
// 加密
|
||||
if len(res.Data.ShortUrl) > 0 {
|
||||
res.Data.ShortUrl = encrypt.AesEncryptCBC([]byte(res.Data.ShortUrl), []byte(this.cfg.SecretKey))
|
||||
}
|
||||
return res, err
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package market
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/config"
|
||||
"fmt"
|
||||
"github.com/qit-team/snow-core/kernel/server"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMarketSendRequest_Market(t *testing.T) {
|
||||
opts := config.GetOptions()
|
||||
if opts.ShowVersion {
|
||||
fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
//加载配置
|
||||
conf, err := config.Load(opts.ConfFile)
|
||||
if err != nil {
|
||||
utils.Log(nil, "err", err.Error())
|
||||
return
|
||||
}
|
||||
client := NewMarketClient(conf.OpenApiMarketConfig)
|
||||
|
||||
//data, err := client.MarketSend("123456789111", "1717567048171", "", "2")
|
||||
data, err := client.MarketSend("123111", "1717", "", "2")
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(data)
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
package market
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// getSignString 使用 xx=aa&yy=bb 的字符串拼接
|
||||
func getSignString(data map[string]interface{}) string {
|
||||
keys := make([]string, 0, len(data))
|
||||
for key := range data {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
signString := ""
|
||||
separator := ""
|
||||
for _, key := range keys {
|
||||
value := data[key]
|
||||
if key == "sign" || value == nil {
|
||||
continue
|
||||
}
|
||||
signString += fmt.Sprintf("%s%s=%v", separator, key, value)
|
||||
separator = "&"
|
||||
}
|
||||
return signString
|
||||
}
|
||||
|
||||
// VerifyRsaSign 签名验证
|
||||
func VerifyRsaSign(publicKey string, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
// 对 sign nonce timestamp appId 升序排序
|
||||
// 使用 xx=aa&yy=bb 的字符串拼接
|
||||
// 商户的公钥验签 RSA2验签
|
||||
signString := getSignString(data)
|
||||
|
||||
rsaPubKey, err := parseRSAPublicKeyFromPEM([]byte(publicKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signature, err := base64.StdEncoding.DecodeString(data["sign"].(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashed := sha256.Sum256([]byte(signString))
|
||||
err = rsa.VerifyPKCS1v15(rsaPubKey, crypto.SHA256, hashed[:], signature)
|
||||
if err != nil {
|
||||
return nil, errors.New("签名验证失败")
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// MakeRsaSign 生成签名
|
||||
func MakeRsaSign(privateKey string, data map[string]interface{}) (string, error) {
|
||||
// 对 sign nonce timestamp appId 升序排序
|
||||
// 使用 xx=aa&yy=bb 的字符串拼接
|
||||
// 营销系统生成的私钥生成签名 RSA2加签
|
||||
signString := getSignString(data)
|
||||
|
||||
privKey, err := parseRSAPrivateKeyFromPEM([]byte(privateKey))
|
||||
if err != nil {
|
||||
return "", errors.New("私钥解析失败")
|
||||
}
|
||||
|
||||
hashed := sha256.Sum256([]byte(signString))
|
||||
signature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, hashed[:])
|
||||
if err != nil {
|
||||
return "", errors.New("签名失败")
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(signature), nil
|
||||
}
|
||||
|
||||
// ParseRSAPrivateKeyFromPEM 解析私钥
|
||||
func parseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, errors.New("私钥解析失败: 无效的PEM格式")
|
||||
}
|
||||
|
||||
var parsedKey interface{}
|
||||
if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
|
||||
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pkey *rsa.PrivateKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
|
||||
return nil, errors.New("密钥不是有效的RSA私钥")
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
||||
|
||||
// parseRSAPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
|
||||
func parseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
|
||||
var err error
|
||||
|
||||
// Parse PEM block
|
||||
var block *pem.Block
|
||||
if block, _ = pem.Decode(key); block == nil {
|
||||
return nil, errors.New("公钥解析失败: 无效的PEM格式")
|
||||
}
|
||||
|
||||
// Parse the key
|
||||
var parsedKey interface{}
|
||||
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
|
||||
if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
|
||||
parsedKey = cert.PublicKey
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var pkey *rsa.PublicKey
|
||||
var ok bool
|
||||
if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
|
||||
return nil, errors.New("密钥不是有效的RSA公钥")
|
||||
}
|
||||
|
||||
return pkey, nil
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
package openapiService
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/models/orderdetailsmodel"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/models/usercouponmodel"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"encoding/base64"
|
||||
"gitee.com/chengdu_blue_brothers/openapi-go-sdk/api"
|
||||
"gitee.com/chengdu_blue_brothers/openapi-go-sdk/notify"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CreatClient() (client *api.Client, err error) {
|
||||
merchantId := config.GetConf().OpenApi.MerchantId
|
||||
secretKey := config.GetConf().OpenApi.SecretKey
|
||||
isProd := config.GetConf().OpenApi.IsProd
|
||||
timeout := 10 * time.Second // 请求超时时间
|
||||
|
||||
client, err = api.NewClient(merchantId, secretKey, isProd, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
type RechargeOrderReq struct {
|
||||
OutTradeNo string
|
||||
ProductId int
|
||||
RechargeAccount string
|
||||
AccountType int
|
||||
Number int
|
||||
}
|
||||
|
||||
func RechargeOrder(rechargeOrderReq RechargeOrderReq) (result *api.RechargeOrderResp, err error) {
|
||||
req := &api.RechargeOrderReq{
|
||||
OutTradeNo: rechargeOrderReq.OutTradeNo,
|
||||
ProductId: rechargeOrderReq.ProductId,
|
||||
RechargeAccount: rechargeOrderReq.RechargeAccount,
|
||||
AccountType: 0,
|
||||
Number: 1,
|
||||
NotifyUrl: config.GetConf().OpenApi.NotifyUrl,
|
||||
}
|
||||
client, err := CreatClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err = client.RechargeOrder(context.Background(), req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Code != api.CodeCreateOrderSuccess {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ReCardOrder(CardOrderReq api.CardOrderReq) (result *api.CardOrderResp, err error) {
|
||||
req := &api.CardOrderReq{
|
||||
OutTradeNo: CardOrderReq.OutTradeNo,
|
||||
ProductId: CardOrderReq.ProductId,
|
||||
AccountType: 0,
|
||||
Number: 1,
|
||||
NotifyUrl: config.GetConf().OpenApi.NotifyUrl,
|
||||
}
|
||||
client, err := CreatClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err = client.CardOrder(context.Background(), req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Code != api.CodeCreateOrderSuccess {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DecryptCard(encCode string) (decode string, err error) {
|
||||
defer func() error {
|
||||
if r := recover(); r != nil {
|
||||
utils.Log(nil, "解密错误", err)
|
||||
|
||||
}
|
||||
return err
|
||||
}()
|
||||
client, err := CreatClient()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
decryptedCode, err := decryptAES(encCode, client.GetSecretKey())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return decryptedCode, nil
|
||||
}
|
||||
|
||||
// AES 解密
|
||||
func decryptAES(encryptedData string, secretKey string) (string, error) {
|
||||
// 第一步:对加密的卡密做base64 decode
|
||||
encryptedBytes, err := base64.StdEncoding.DecodeString(encryptedData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 第二步:使用aes-256-ecb解密
|
||||
cipher, _ := aes.NewCipher([]byte(secretKey))
|
||||
decrypted := make([]byte, len(encryptedBytes))
|
||||
size := 16
|
||||
for bs, be := 0, size; bs < len(encryptedBytes); bs, be = bs+size, be+size {
|
||||
cipher.Decrypt(decrypted[bs:be], encryptedBytes[bs:be])
|
||||
}
|
||||
paddingSize := int(decrypted[len(decrypted)-1])
|
||||
return string(decrypted[0 : len(decrypted)-paddingSize]), nil
|
||||
}
|
||||
|
||||
func ParseAndVerify(request *http.Request) (req *notify.OrderReq, err error) {
|
||||
// 第一步:初使化client实例
|
||||
merchantId := config.GetConf().OpenApi.MerchantId
|
||||
secretKey := config.GetConf().OpenApi.SecretKey
|
||||
client := notify.NewNotify(merchantId, secretKey)
|
||||
|
||||
// 第二步:验签并解析结果
|
||||
req, err = client.ParseAndVerify(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NotifyOperation /**
|
||||
func NotifyOperation(order ordersmodel.Orders, req *notify.OrderReq) (err error) {
|
||||
var session = ordersmodel.GetInstance().GetDb().NewSession()
|
||||
session.Begin()
|
||||
updateOrder := ordersmodel.Orders{Status: 3}
|
||||
_, err = session.Where("Id = ?", order.Id).Update(&updateOrder)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return
|
||||
}
|
||||
//卡密
|
||||
if req.CardCode != "" {
|
||||
//订单详情
|
||||
updateOrderDetail := orderdetailsmodel.OrderDetails{Url: req.CardCode.Value()}
|
||||
_, err = session.Where("OrderId = ?", order.Id).Update(&updateOrderDetail)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return
|
||||
}
|
||||
userCouponDetail := usercouponmodel.UserCoupon{OrderInfo: req.CardCode.Value()}
|
||||
_, err = session.Where("OrderId = ?", order.Id).Update(&userCouponDetail)
|
||||
if err != nil {
|
||||
session.Rollback()
|
||||
return
|
||||
}
|
||||
}
|
||||
session.Commit()
|
||||
return
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
package paymentService
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/services/thirdpay/thirdpay_notify"
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// AliInitClient 使用提供的支付请求参数初始化支付宝客户端
|
||||
func AliInitClient(aliConfig AliPay) (*alipay.Client, error) {
|
||||
envConfig := config.GetConf()
|
||||
// 初始化支付宝客户端
|
||||
// appid:应用ID
|
||||
// privateKey:应用私钥,支持PKCS1和PKCS8
|
||||
// isProd:是否是正式环境,沙箱环境请选择新版沙箱应用。
|
||||
aliClient, aliClientErr := alipay.NewClient(aliConfig.AppId, aliConfig.PrivateKey, envConfig.PayService.IsProd)
|
||||
// 自定义配置http请求接收返回结果body大小,默认 10MB
|
||||
aliClient.SetBodySize(10) // 没有特殊需求,可忽略此配置
|
||||
|
||||
// 打开Debug开关,输出日志,默认关闭
|
||||
aliClient.DebugSwitch = gopay.DebugOn
|
||||
|
||||
// 设置支付宝请求 公共参数
|
||||
// 注意:具体设置哪些参数,根据不同的方法而不同,此处列举出所有设置参数
|
||||
aliClient.SetLocation(alipay.LocationShanghai). // 设置时区,不设置或出错均为默认服务器时间
|
||||
SetCharset(alipay.UTF8). // 设置字符编码,不设置默认 utf-8
|
||||
SetSignType(alipay.RSA2) // 设置签名类型,不设置默认 RSA2
|
||||
|
||||
// 自动同步验签(只支持证书模式)
|
||||
// 传入 alipayPublicCert.crt 内容
|
||||
aliClient.AutoVerifySign([]byte(aliConfig.AlipayPublicCert))
|
||||
|
||||
// 证书内容
|
||||
aliClientErr = aliClient.SetCertSnByContent([]byte(aliConfig.AppPublicCert), []byte(aliConfig.AlipayRootCert), []byte(aliConfig.AlipayPublicCert))
|
||||
if aliClient == nil {
|
||||
return nil, errors.New("client not initialized")
|
||||
}
|
||||
if aliClientErr != nil {
|
||||
return nil, aliClientErr
|
||||
}
|
||||
return aliClient, nil
|
||||
}
|
||||
|
||||
// ALiH5PayInfo 支付宝手机网站支付
|
||||
func ALiH5PayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) {
|
||||
// 初始化支付宝客户端
|
||||
aliClient, err := AliInitClient(payOrderRequest.Ali)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get client:", err)
|
||||
return "", err
|
||||
}
|
||||
// 初始化 BodyMap
|
||||
amount := float64(payOrderRequest.Amount) / 100.0
|
||||
|
||||
envConfig := config.GetConf()
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("out_trade_no", payOrderRequest.OrderId).
|
||||
Set("total_amount", amount).
|
||||
Set("subject", payOrderRequest.Description).
|
||||
Set("notify_url", fmt.Sprintf(envConfig.PayService.Host+payCommon.ALI_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId))
|
||||
|
||||
aliRsp, err := aliClient.TradeWapPay(c, bm)
|
||||
if err != nil {
|
||||
logger.Error(c, "ALiH5PayInfo 发生错误", fmt.Sprintf("错误信息:%s", err.Error()))
|
||||
if bizErr, ok := alipay.IsBizError(err); ok {
|
||||
return "", bizErr
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return aliRsp, nil
|
||||
}
|
||||
|
||||
// ALiCallBack 支付宝支付回调
|
||||
func ALiCallBack(notifyReq gopay.BodyMap, aliConfig AliPay) error {
|
||||
ok, err := alipay.VerifySignWithCert([]byte(aliConfig.AlipayPublicCert), notifyReq)
|
||||
if !ok || err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 拼装数据触发下游回调,触发下游回调
|
||||
orderId, _ := strconv.Atoi(notifyReq.Get("out_trade_no"))
|
||||
payerTotal, _ := strconv.Atoi(notifyReq.Get("buyer_pay_amount"))
|
||||
// 订单状态
|
||||
tradeStatus := notifyReq.Get("trade_status")
|
||||
errCode := 0
|
||||
msg := ""
|
||||
switch tradeStatus {
|
||||
case "TRADE_CLOSED":
|
||||
errCode = errorcode.ParamError
|
||||
msg = "未付款交易超时关闭,或支付完成后全额退款。"
|
||||
case "TRADE_SUCCESS":
|
||||
errCode = errorcode.Success
|
||||
msg = "交易支付成功。"
|
||||
case "TRADE_FINISHED":
|
||||
errCode = errorcode.Success
|
||||
msg = "交易结束,不可退款。"
|
||||
}
|
||||
if errCode == 0 {
|
||||
// 等待买家付款,不走后续回调
|
||||
return errors.New("订单状态异常,无法进行后续回调")
|
||||
}
|
||||
|
||||
res := thirdpay_notify.NewOrderNotifyWithHandle(int64(orderId), errCode, payerTotal, msg)
|
||||
merchantCallback, _ := json.Marshal(res)
|
||||
// 记录日志
|
||||
go func() {
|
||||
payCallback, _ := json.Marshal(notifyReq)
|
||||
payParam := "{}"
|
||||
status := common.THIRD_ORDER_LOG_STATUS_SUCCESS
|
||||
SaveLog(int64(orderId), common.THIRD_ORDER_TYPE_CALL_BACK, string(payCallback), payParam, "{}", status)
|
||||
}()
|
||||
|
||||
if res.ErrCode != errorcode.Success {
|
||||
logger.Error(context.Background(), "ALiCallBack 发生错误", fmt.Sprintf("回调时,下游处理订单失败,返回数据为:%s", string(merchantCallback)))
|
||||
return errors.New("回调时,下游处理订单失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ALiOrderQuery 查询支付宝订单
|
||||
func ALiOrderQuery(ctx context.Context, aliConfig AliPay, OrderNo string) (PayOrderQueryInfo, error) {
|
||||
// 初始化支付宝客户端
|
||||
aliClient, err := AliInitClient(aliConfig)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get client:", err)
|
||||
return PayOrderQueryInfo{}, err
|
||||
}
|
||||
|
||||
// 请求参数
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("out_trade_no", OrderNo)
|
||||
|
||||
// 查询订单
|
||||
aliRsp, err := aliClient.TradeQuery(ctx, bm)
|
||||
if err != nil {
|
||||
if bizErr, ok := alipay.IsBizError(err); ok {
|
||||
return PayOrderQueryInfo{}, bizErr
|
||||
}
|
||||
return PayOrderQueryInfo{}, err
|
||||
}
|
||||
// 同步返回验签
|
||||
ok, err := alipay.VerifySyncSignWithCert([]byte(aliConfig.AlipayPublicCert), aliRsp.SignData, aliRsp.Sign)
|
||||
if err != nil || !ok {
|
||||
return PayOrderQueryInfo{}, errors.New(fmt.Sprintf("验签失败,失败原因:%s", err.Error()))
|
||||
}
|
||||
|
||||
// 映射交易状态
|
||||
tradeState := ""
|
||||
tradeStateDesc := ""
|
||||
switch aliRsp.Response.TradeStatus {
|
||||
case "TRADE_SUCCESS":
|
||||
tradeState = "SUCCESS"
|
||||
tradeStateDesc = "交易支付成功"
|
||||
case "REFUND":
|
||||
tradeState = "REFUND"
|
||||
tradeStateDesc = "转入退款"
|
||||
case "WAIT_BUYER_PAY":
|
||||
tradeState = "NOTPAY"
|
||||
tradeStateDesc = "交易创建,等待买家付款"
|
||||
case "TRADE_CLOSED":
|
||||
tradeState = "CLOSED"
|
||||
tradeStateDesc = "未付款交易超时关闭,或支付完成后全额退款"
|
||||
}
|
||||
|
||||
amountTotal, _ := strconv.ParseFloat(aliRsp.Response.TotalAmount, 64)
|
||||
payerTotal, _ := strconv.ParseFloat(aliRsp.Response.BuyerPayAmount, 64)
|
||||
// 构建数据
|
||||
outTradeNo, _ := strconv.Atoi(aliRsp.Response.OutTradeNo)
|
||||
return PayOrderQueryInfo{
|
||||
AppId: aliConfig.AppId,
|
||||
OutTradeNo: int64(outTradeNo),
|
||||
TransactionId: aliRsp.Response.TradeNo,
|
||||
TradeState: tradeState,
|
||||
TradeStateDesc: tradeStateDesc,
|
||||
SuccessTime: aliRsp.Response.SendPayDate,
|
||||
AmountTotal: int64(amountTotal * 100),
|
||||
PayerTotal: int64(payerTotal * 100),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AliRefundOrder 支付宝退款申请
|
||||
func AliRefundOrder(ctx context.Context, orderRefundRequest OrderRefundRequest) (OrderRefundInfo, error) {
|
||||
// 初始化支付宝客户端
|
||||
aliClient, err := AliInitClient(orderRefundRequest.Ali)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get client:", err)
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
|
||||
// 请求参数
|
||||
refundAmount := float64(orderRefundRequest.RefundAmount) / 100.0
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("out_trade_no", orderRefundRequest.OrderId).
|
||||
Set("refund_amount", refundAmount).
|
||||
Set("refund_reason", orderRefundRequest.RefundReason).
|
||||
Set("out_request_no", orderRefundRequest.RefundOrderId)
|
||||
|
||||
// 发起退款请求
|
||||
aliRsp, err := aliClient.TradeRefund(ctx, bm)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "AliRefundOrder 发生错误", fmt.Sprintf("申请退款接口失败,错误信息:%s", err.Error()))
|
||||
if bizErr, ok := alipay.IsBizError(err); ok {
|
||||
return OrderRefundInfo{}, bizErr
|
||||
}
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
|
||||
refundFee, _ := strconv.ParseFloat(aliRsp.Response.RefundFee, 64)
|
||||
outTradeNo, _ := strconv.ParseFloat(aliRsp.Response.OutTradeNo, 64)
|
||||
return OrderRefundInfo{
|
||||
OutTradeNo: int64(outTradeNo),
|
||||
TransactionId: aliRsp.Response.TradeNo,
|
||||
RefundFee: int64(refundFee * 100),
|
||||
RefundOrderId: orderRefundRequest.RefundOrderId,
|
||||
RefundStatus: payCommon.PAY_REFUND_STATU_SUCCESS,
|
||||
RefundSuccessTime: aliRsp.Response.GmtRefundPay,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AliRefundOrderQuery 支付宝订单退款查询
|
||||
func AliRefundOrderQuery(ctx context.Context, orderRefundQueryRequest OrderRefundQueryRequest) (OrderRefundInfo, error) {
|
||||
// 初始化支付宝客户端
|
||||
aliClient, err := AliInitClient(orderRefundQueryRequest.Ali)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get client:", err)
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
|
||||
// 请求参数
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("out_trade_no", orderRefundQueryRequest.OrderId).
|
||||
Set("out_request_no", orderRefundQueryRequest.RefundOrderId).
|
||||
Set("query_options", []string{"gmt_refund_pay"})
|
||||
|
||||
// 发起退款查询请求
|
||||
aliRsp, err := aliClient.TradeFastPayRefundQuery(ctx, bm)
|
||||
if err != nil {
|
||||
if bizErr, ok := alipay.IsBizError(err); ok {
|
||||
return OrderRefundInfo{}, bizErr
|
||||
}
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
refundFee, _ := strconv.ParseFloat(aliRsp.Response.RefundAmount, 64)
|
||||
outTradeNo, _ := strconv.Atoi(aliRsp.Response.OutTradeNo)
|
||||
refundOrderId, _ := strconv.Atoi(aliRsp.Response.OutRequestNo)
|
||||
return OrderRefundInfo{
|
||||
OutTradeNo: int64(outTradeNo),
|
||||
TransactionId: aliRsp.Response.TradeNo,
|
||||
RefundFee: int64(refundFee * 100),
|
||||
RefundOrderId: int64(refundOrderId),
|
||||
RefundStatus: payCommon.PAY_REFUND_STATU_SUCCESS,
|
||||
RefundSuccessTime: aliRsp.Response.GmtRefundPay,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AliCloseOrder 支付宝订单关闭
|
||||
func AliCloseOrder(ctx context.Context, orderCloseRequest OrderCloseRequest) (OrderCloseInfo, error) {
|
||||
// 初始化支付宝客户端
|
||||
aliClient, err := AliInitClient(orderCloseRequest.Ali)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get client:", err)
|
||||
return OrderCloseInfo{}, err
|
||||
}
|
||||
// 请求参数
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("out_trade_no", orderCloseRequest.OrderId)
|
||||
|
||||
// 关闭订单
|
||||
aliRsp, err := aliClient.TradeClose(ctx, bm)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "AliCloseOrder 发生错误", fmt.Sprintf("申请退款接口失败,错误信息:%s", err.Error()))
|
||||
if bizErr, ok := alipay.IsBizError(err); ok {
|
||||
return OrderCloseInfo{}, bizErr
|
||||
}
|
||||
return OrderCloseInfo{}, err
|
||||
}
|
||||
|
||||
outTradeNo, _ := strconv.Atoi(aliRsp.Response.OutTradeNo)
|
||||
return OrderCloseInfo{
|
||||
OutTradeNo: int64(outTradeNo),
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package payCommon
|
||||
|
||||
import "PaymentCenter/app/constants/common"
|
||||
|
||||
const (
|
||||
|
||||
// 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||
PAY_CHANNEL_UNKNOWN = 0
|
||||
PAY_CHANNEL_WECHAT_JSAPI = 1
|
||||
PAY_CHANNEL_WECHAT_H5 = 2
|
||||
PAY_CHANNEL_WECHAT_APP = 3
|
||||
PAY_CHANNEL_WECHAT_NATIVE = 4
|
||||
PAY_CHANNEL_WECHAT_MINI = 5
|
||||
PAY_CHANNEL_ALIPAY_WEB = 6
|
||||
PAY_CHANNEL_ALIPAY_MINI = 7
|
||||
PAY_CHANNEL_ALIPAY_JSAPI = 8
|
||||
|
||||
PAY_SUCCESS_CODE = 200 // 支付响应成功
|
||||
PAY_ERROR_CODE = 500 // 支付响应失败
|
||||
PAY_NOT_FOUND_CODE = 404 // 未找到支付渠道
|
||||
|
||||
WX_SUCCESS_CODE = 200 // 微信状态码返回成功
|
||||
|
||||
WX_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
|
||||
WX_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
|
||||
ALI_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
|
||||
ALI_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
|
||||
|
||||
ORDER_NO_TYPE_ORDER_NO = 2
|
||||
|
||||
PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信
|
||||
PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝
|
||||
|
||||
PAY_REFUND_STATU_COMMON = 0 // 未申请
|
||||
PAY_REFUND_STATU_ING = 1 // 退款中
|
||||
PAY_REFUND_STATU_SUCCESS = 2 // 退款成功
|
||||
PAY_REFUND_STATU_FAIL = 3 // 退款失败
|
||||
)
|
|
@ -0,0 +1,367 @@
|
|||
package paymentService
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/data"
|
||||
"PaymentCenter/app/models/orderthirdpaylogmodel"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type PayOrderRequest struct {
|
||||
PayChannelId int64 `json:"pay_channel_id"` // 支付方式ID
|
||||
OrderId int64 `json:"order_id"` // 平台订单号
|
||||
ChannelType int `json:"channel_type"` // 支付方式
|
||||
Description string `json:"description"` // 商品描述
|
||||
Amount int `json:"amount"` // 金额单位为分
|
||||
PayerClientIp string `json:"payer_client_ip"` // 终端IP
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
}
|
||||
|
||||
type WxPay struct {
|
||||
AppId string `json:"app_id"` // 应用ID
|
||||
MchId string `json:"mch_id"` // 商户ID 或者服务商模式的 sp_mchid
|
||||
SerialNo string `json:"serial_no"` // 商户证书的证书序列号
|
||||
ApiV3Key string `json:"api_v_3_key"` // apiV3Key,商户平台获取
|
||||
PrivateKey string `json:"private_key"` // 私钥 apiclient_key.pem 读取后的内容
|
||||
}
|
||||
|
||||
type AliPay struct {
|
||||
AppId string `json:"app_id"` // 应用ID
|
||||
PrivateKey string `json:"private_key"` // 应用私钥
|
||||
AppPublicCert string `json:"app_public_cert"` // 应用公钥
|
||||
AlipayRootCert string `json:"alipay_root_cert"` // 支付宝根证书
|
||||
AlipayPublicCert string `json:"alipay_public_cert"` // 支付宝公钥
|
||||
}
|
||||
|
||||
type PayOrderResponse struct {
|
||||
Code int `json:"code"`
|
||||
ErrorMsg string `json:"error_msg"`
|
||||
Result string `json:"result"`
|
||||
}
|
||||
|
||||
// PaymentService 统一发起支付
|
||||
func PaymentService(c context.Context, payOrderRequest PayOrderRequest) PayOrderResponse {
|
||||
//logger.Info(c, "PaymentService 收到支付请求", payOrderRequest)
|
||||
var err error
|
||||
var info string
|
||||
var payOrderResponse PayOrderResponse
|
||||
switch payOrderRequest.ChannelType {
|
||||
case payCommon.PAY_CHANNEL_WECHAT_H5:
|
||||
// 微信H5支付
|
||||
info, err = WxH5PayInfo(c, payOrderRequest)
|
||||
case payCommon.PAY_CHANNEL_ALIPAY_WEB:
|
||||
// 支付宝H5支付
|
||||
info, err = ALiH5PayInfo(c, payOrderRequest)
|
||||
default:
|
||||
payOrderResponse = PayOrderResponse{
|
||||
Code: payCommon.PAY_NOT_FOUND_CODE,
|
||||
ErrorMsg: "暂不支持该支付渠道,请后续再使用",
|
||||
}
|
||||
}
|
||||
|
||||
logStatus := common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
if err != nil {
|
||||
payOrderResponse = PayOrderResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: err.Error(),
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
} else if payOrderResponse.ErrorMsg == "" {
|
||||
payOrderResponse = PayOrderResponse{
|
||||
Code: payCommon.PAY_SUCCESS_CODE,
|
||||
ErrorMsg: "",
|
||||
Result: info,
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_SUCCESS
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
go func() {
|
||||
orderId := payOrderRequest.OrderId
|
||||
payCallback := fmt.Sprintf("{%s}", info)
|
||||
payParam, _ := json.Marshal(payOrderRequest)
|
||||
merchantCallback, _ := json.Marshal(payOrderResponse)
|
||||
SaveLog(orderId, common.THIRD_ORDER_TYPE_PAY, payCallback, string(payParam), string(merchantCallback), logStatus)
|
||||
}()
|
||||
return payOrderResponse
|
||||
}
|
||||
|
||||
type PayOrderQueryRequest struct {
|
||||
OrderId int64 `json:"order_id"` // 商户订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
}
|
||||
|
||||
type PayOrderQueryResponse struct {
|
||||
Code int `json:"code"`
|
||||
ErrorMsg string `json:"error_msg"`
|
||||
Result PayOrderQueryInfo `json:"result"`
|
||||
}
|
||||
|
||||
type PayOrderQueryInfo struct {
|
||||
AppId string `json:"app_id"` // 应用ID
|
||||
OutTradeNo int64 `json:"out_trade_no"` // 商家订单号
|
||||
TransactionId string `json:"transaction_id"` // 第三方订单号
|
||||
TradeState string `json:"trade_state"` // 交易状态 SUCCESS:成功、REFUND:转入退款、NOTPAY:未支付、CLOSED:已关闭
|
||||
TradeStateDesc string `json:"trade_state_desc"` // 交易描述
|
||||
SuccessTime string `json:"success_time"` // 交易完成时间
|
||||
AmountTotal int64 `json:"amount_total"` // 订单总金额,单位:分
|
||||
PayerTotal int64 `json:"payer_total"` // 支付总金额,单位:分
|
||||
}
|
||||
|
||||
// PayOrderQuery 查询订单状态
|
||||
func PayOrderQuery(c context.Context, payOrderQueryRequest PayOrderQueryRequest) PayOrderQueryResponse {
|
||||
var err error
|
||||
var info PayOrderQueryInfo
|
||||
var payOrderQueryResponse PayOrderQueryResponse
|
||||
switch payOrderQueryRequest.PayChannel {
|
||||
case payCommon.PAY_CHANNLE_TYPE_WECHAT:
|
||||
// 微信H5支付
|
||||
info, err = WxOrderQuery(c, payOrderQueryRequest.Wx, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
|
||||
case payCommon.PAY_CHANNLE_TYPE_ZFB:
|
||||
info, err = ALiOrderQuery(c, payOrderQueryRequest.Ali, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
|
||||
default:
|
||||
payOrderQueryResponse = PayOrderQueryResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: "暂不支持该支付渠道,请后续再使用",
|
||||
}
|
||||
}
|
||||
|
||||
logStatus := common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
if err != nil {
|
||||
payOrderQueryResponse = PayOrderQueryResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: err.Error(),
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
} else if payOrderQueryResponse.ErrorMsg == "" {
|
||||
payOrderQueryResponse = PayOrderQueryResponse{
|
||||
Code: payCommon.PAY_SUCCESS_CODE,
|
||||
Result: info,
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_SUCCESS
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
go func() {
|
||||
orderId := payOrderQueryRequest.OrderId
|
||||
payCallback, _ := json.Marshal(info)
|
||||
payParam, _ := json.Marshal(payOrderQueryRequest)
|
||||
merchantCallback, _ := json.Marshal(payOrderQueryResponse)
|
||||
SaveLog(orderId, common.THIRD_ORDER_TYPE_ORDER_QUERY, string(payCallback), string(payParam), string(merchantCallback), logStatus)
|
||||
}()
|
||||
return payOrderQueryResponse
|
||||
}
|
||||
|
||||
type OrderRefundRequest struct {
|
||||
OrderId int64 `json:"order_id"` // 订单编号
|
||||
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
|
||||
RefundReason string `json:"refund_reason"` // 退款原因
|
||||
RefundAmount int64 `json:"refund_amount"` // 退款金额,单位分
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
}
|
||||
|
||||
type OrderRefundResponse struct {
|
||||
Code int `json:"code"`
|
||||
ErrorMsg string `json:"error_msg"`
|
||||
Result OrderRefundInfo `json:"result"`
|
||||
}
|
||||
|
||||
type OrderRefundInfo struct {
|
||||
OutTradeNo int64 `json:"out_trade_no"` // 商家订单号
|
||||
TransactionId string `json:"transaction_id"` // 第三方订单号
|
||||
RefundFee int64 `json:"refund_fee"` // 退款金额
|
||||
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
|
||||
RefundStatus int `json:"refund_status"` // 退款状态 0:未申请,1:退款中,2:退款成功,3:退款失败
|
||||
RefundSuccessTime string `json:"refund_success_time"` // 退款时间
|
||||
}
|
||||
|
||||
// OrderRefund 订单退款
|
||||
func OrderRefund(c context.Context, orderRefundRequest OrderRefundRequest) OrderRefundResponse {
|
||||
//logger.Info(c, "PaymentService 收到退款请求", orderRefundRequest)
|
||||
var err error
|
||||
var info OrderRefundInfo
|
||||
var orderRefundResponse OrderRefundResponse
|
||||
switch orderRefundRequest.PayChannel {
|
||||
case payCommon.PAY_CHANNLE_TYPE_WECHAT:
|
||||
// 微信H5支付
|
||||
info, err = WxOrderRefund(c, orderRefundRequest)
|
||||
case payCommon.PAY_CHANNLE_TYPE_ZFB:
|
||||
info, err = AliRefundOrder(c, orderRefundRequest)
|
||||
default:
|
||||
orderRefundResponse = OrderRefundResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: "暂不支持该支付渠道,请后续再使用",
|
||||
}
|
||||
}
|
||||
|
||||
logStatus := common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
if err != nil {
|
||||
orderRefundResponse = OrderRefundResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: err.Error(),
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
} else if orderRefundResponse.ErrorMsg == "" {
|
||||
orderRefundResponse = OrderRefundResponse{
|
||||
Code: payCommon.PAY_SUCCESS_CODE,
|
||||
Result: info,
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_SUCCESS
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
go func() {
|
||||
orderId := orderRefundRequest.OrderId
|
||||
payCallback, _ := json.Marshal(info)
|
||||
payParam, _ := json.Marshal(orderRefundRequest)
|
||||
merchantCallback, _ := json.Marshal(orderRefundResponse)
|
||||
SaveLog(orderId, common.THIRD_ORDER_TYPE_REFUND, string(payCallback), string(payParam), string(merchantCallback), logStatus)
|
||||
}()
|
||||
return orderRefundResponse
|
||||
}
|
||||
|
||||
type OrderRefundQueryRequest struct {
|
||||
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
|
||||
OrderId int64 `json:"order_id"` // 支付订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
}
|
||||
type OrderRefundQueryResponse struct {
|
||||
Code int `json:"code"`
|
||||
ErrorMsg string `json:"error_msg"`
|
||||
Result OrderRefundInfo `json:"result"`
|
||||
}
|
||||
|
||||
// OrderRefundQuery 订单退款查询
|
||||
func OrderRefundQuery(c context.Context, orderRefundQueryRequest OrderRefundQueryRequest) OrderRefundQueryResponse {
|
||||
var err error
|
||||
var info OrderRefundInfo
|
||||
var orderRefundQueryResponse OrderRefundQueryResponse
|
||||
switch orderRefundQueryRequest.PayChannel {
|
||||
case payCommon.PAY_CHANNLE_TYPE_WECHAT:
|
||||
// 微信H5支付
|
||||
info, err = WxOrderRefundQuery(c, orderRefundQueryRequest)
|
||||
case payCommon.PAY_CHANNLE_TYPE_ZFB:
|
||||
info, err = AliRefundOrderQuery(c, orderRefundQueryRequest)
|
||||
default:
|
||||
orderRefundQueryResponse = OrderRefundQueryResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: "暂不支持该支付渠道,请后续再使用",
|
||||
}
|
||||
}
|
||||
|
||||
logStatus := common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
if err != nil {
|
||||
orderRefundQueryResponse = OrderRefundQueryResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: err.Error(),
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
} else if orderRefundQueryResponse.ErrorMsg == "" {
|
||||
orderRefundQueryResponse = OrderRefundQueryResponse{
|
||||
Code: payCommon.PAY_SUCCESS_CODE,
|
||||
Result: info,
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_SUCCESS
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
go func() {
|
||||
orderId := orderRefundQueryRequest.OrderId
|
||||
payCallback, _ := json.Marshal(info)
|
||||
payParam, _ := json.Marshal(orderRefundQueryRequest)
|
||||
merchantCallback, _ := json.Marshal(orderRefundQueryResponse)
|
||||
SaveLog(orderId, common.THIRD_ORDER_TYPE_REFUND_QUERY, string(payCallback), string(payParam), string(merchantCallback), logStatus)
|
||||
}()
|
||||
return orderRefundQueryResponse
|
||||
}
|
||||
|
||||
type OrderCloseRequest struct {
|
||||
OrderId int64 `json:"order_id"` // 支付订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
}
|
||||
|
||||
type OrderCloseResponse struct {
|
||||
Code int `json:"code"`
|
||||
ErrorMsg string `json:"error_msg"`
|
||||
Result OrderCloseInfo `json:"result"`
|
||||
}
|
||||
|
||||
type OrderCloseInfo struct {
|
||||
OutTradeNo int64 `json:"out_trade_no"` // 商家订单号
|
||||
}
|
||||
|
||||
// OrderClose 关闭订单
|
||||
func OrderClose(c context.Context, orderCloseRequest OrderCloseRequest) OrderCloseResponse {
|
||||
//logger.Info(c, "PaymentService 收到关闭订单请求", orderCloseRequest)
|
||||
var err error
|
||||
var info OrderCloseInfo
|
||||
var orderCloseResponse OrderCloseResponse
|
||||
switch orderCloseRequest.PayChannel {
|
||||
case payCommon.PAY_CHANNLE_TYPE_WECHAT:
|
||||
// 微信H5支付
|
||||
info, err = WxCloseOrder(c, orderCloseRequest)
|
||||
case payCommon.PAY_CHANNLE_TYPE_ZFB:
|
||||
info, err = AliCloseOrder(c, orderCloseRequest)
|
||||
default:
|
||||
orderCloseResponse = OrderCloseResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: "暂不支持该支付渠道,请后续再使用",
|
||||
}
|
||||
}
|
||||
|
||||
logStatus := common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
if err != nil {
|
||||
orderCloseResponse = OrderCloseResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
ErrorMsg: err.Error(),
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
} else if orderCloseResponse.ErrorMsg == "" {
|
||||
orderCloseResponse = OrderCloseResponse{
|
||||
Code: payCommon.PAY_SUCCESS_CODE,
|
||||
Result: info,
|
||||
}
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_SUCCESS
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
go func() {
|
||||
orderId := orderCloseRequest.OrderId
|
||||
payCallback, _ := json.Marshal(info)
|
||||
payParam, _ := json.Marshal(orderCloseRequest)
|
||||
merchantCallback, _ := json.Marshal(orderCloseResponse)
|
||||
SaveLog(orderId, common.THIRD_ORDER_TYPE_CLOSE, string(payCallback), string(payParam), string(merchantCallback), logStatus)
|
||||
}()
|
||||
return orderCloseResponse
|
||||
}
|
||||
|
||||
// SaveLog 记录操作日志
|
||||
func SaveLog(orderId int64, OType int, payCallback string, PayParam string, MerchantCallback string, status int) {
|
||||
thirdRepo := data.NewOrderThirdPayLogRepo(paychannelmodel.GetInstance().GetDb())
|
||||
log := orderthirdpaylogmodel.OrderThirdPayLog{
|
||||
OrderId: orderId,
|
||||
PayCallback: payCallback,
|
||||
Status: status,
|
||||
PayParam: PayParam,
|
||||
MerchantCallback: MerchantCallback,
|
||||
Type: OType,
|
||||
}
|
||||
_, err := thirdRepo.OrderThirdPayLogInsertOne(&log)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,323 @@
|
|||
package paymentService
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/services/thirdpay/thirdpay_notify"
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/wechat/v3"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InitClient 使用提供的支付请求参数初始化微信客户端
|
||||
func InitClient(wxConfig WxPay) (*wechat.ClientV3, error) {
|
||||
// NewClientV3 初始化微信客户端 v3
|
||||
// mchid:商户ID 或者服务商模式的 sp_mchid
|
||||
// serialNo:商户证书的证书序列号
|
||||
// apiV3Key:apiV3Key,商户平台获取
|
||||
// privateKey:私钥 apiclient_key.pem 读取后的内容
|
||||
wxClient, clientErr := wechat.NewClientV3(
|
||||
wxConfig.MchId,
|
||||
wxConfig.SerialNo,
|
||||
wxConfig.ApiV3Key,
|
||||
wxConfig.PrivateKey,
|
||||
)
|
||||
// 启用自动同步返回验签,并定时更新微信平台API证书(开启自动验签时,无需单独设置微信平台API证书和序列号)
|
||||
clientErr = wxClient.AutoVerifySign()
|
||||
if wxClient == nil {
|
||||
return nil, errors.New("client not initialized")
|
||||
}
|
||||
if clientErr != nil {
|
||||
return nil, clientErr
|
||||
}
|
||||
|
||||
// 自定义配置http请求接收返回结果body大小,默认 10MB
|
||||
wxClient.SetBodySize(10) // 没有特殊需求,可忽略此配置
|
||||
|
||||
// 打开Debug开关,输出日志,默认是关闭的
|
||||
wxClient.DebugSwitch = gopay.DebugOn
|
||||
return wxClient, nil
|
||||
|
||||
}
|
||||
|
||||
// WxH5PayInfo 微信H5支付
|
||||
func WxH5PayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) {
|
||||
// 初始化微信客户端
|
||||
wxClient, err := InitClient(payOrderRequest.Wx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
expire := time.Now().Add(10 * time.Minute).Format(time.RFC3339)
|
||||
// 初始化 BodyMap
|
||||
envConfig := config.GetConf()
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("appid", payOrderRequest.Wx.AppId).
|
||||
Set("mchid", payOrderRequest.Wx.MchId).
|
||||
Set("description", payOrderRequest.Description).
|
||||
Set("out_trade_no", strconv.FormatInt(payOrderRequest.OrderId, 10)).
|
||||
Set("time_expire", expire).
|
||||
Set("notify_url", fmt.Sprintf(envConfig.PayService.Host+payCommon.WX_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)).
|
||||
SetBodyMap("amount", func(bm gopay.BodyMap) {
|
||||
bm.Set("total", payOrderRequest.Amount).
|
||||
Set("currency", "CNY")
|
||||
}).
|
||||
SetBodyMap("scene_info", func(bm gopay.BodyMap) {
|
||||
bm.Set("payer_client_ip", payOrderRequest.PayerClientIp).
|
||||
SetBodyMap("h5_info", func(bm gopay.BodyMap) {
|
||||
bm.Set("type", "common")
|
||||
})
|
||||
})
|
||||
|
||||
wxRsp, err := wxClient.V3TransactionH5(c, bm)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if wxRsp.Code != wechat.Success || wxRsp.Response.H5Url == "" {
|
||||
logger.Error(c, "WxH5PayInfo 发生错误", fmt.Sprintf("错误状态码:%d, 错误信息:%s", wxRsp.Code, wxRsp.Error))
|
||||
return "", errors.New(fmt.Sprintf("发起支付失败,失败状态码:%d, 失败原因:%s", wxRsp.Code, wxRsp.Error))
|
||||
}
|
||||
return wxRsp.Response.H5Url, nil
|
||||
}
|
||||
|
||||
// WxPayCallBack 微信支付回调
|
||||
func WxPayCallBack(notifyReq *wechat.V3NotifyReq, wxConfig WxPay) error {
|
||||
// 初始化微信客户端
|
||||
wxClient, err := InitClient(wxConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取微信平台证书
|
||||
certMap := wxClient.WxPublicKeyMap()
|
||||
// 验证异步通知的签名
|
||||
err = notifyReq.VerifySignByPKMap(certMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var CallBackInfo struct {
|
||||
AppId string `json:"app_id"` // 应用ID
|
||||
Mchid string `json:"mchid"` // 商户号
|
||||
OutTradeNo string `json:"out_trade_no"` // 商户系统内部订单号
|
||||
TransactionId string `json:"transaction_id"` // 微信系统订单号
|
||||
TradeType string `json:"trade_type"` // JSAPI:公众号支付 NATIVE:扫码支付 App:App支付 MICROPAY:付款码支付 MWEB:H5支付 FACEPAY:刷脸支付
|
||||
TradeState string `json:"trade_state"` // SUCCESS:支付成功 REFUND:转入退款 NOTPAY:未支付 CLOSED:已关闭 REVOKED:已撤销(付款码支付) USERPAYING:用户支付中(付款码支付) PAYERROR:支付失败(其他原因,如银行返回失败)
|
||||
TradeStateDesc string `json:"trade_state_desc"` // 交易状态描述
|
||||
SuccessTime string `json:"success_time"` // 支付完成时间
|
||||
Amount struct {
|
||||
Total int64 `json:"total"`
|
||||
PayerTotal int64 `json:"payer_total"`
|
||||
} `json:"amount"`
|
||||
}
|
||||
// 通用通知解密(推荐此方法)
|
||||
err = notifyReq.DecryptCipherTextToStruct(wxConfig.ApiV3Key, &CallBackInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errCode := 0
|
||||
msg := ""
|
||||
// 订单状态
|
||||
switch CallBackInfo.TradeState {
|
||||
case "SUCCESS":
|
||||
errCode = errorcode.Success
|
||||
msg = "支付成功"
|
||||
case "CLOSED":
|
||||
errCode = errorcode.ParamError
|
||||
msg = "已关闭"
|
||||
case "REVOKED":
|
||||
errCode = errorcode.ParamError
|
||||
msg = "已撤销(付款码支付)"
|
||||
case "PAYERROR":
|
||||
errCode = errorcode.ParamError
|
||||
msg = "支付失败(其他原因,如银行返回失败)"
|
||||
}
|
||||
|
||||
// 触发下游回调的格式
|
||||
orderId, _ := strconv.Atoi(CallBackInfo.OutTradeNo)
|
||||
res := thirdpay_notify.NewOrderNotifyWithHandle(int64(orderId), errCode, int(CallBackInfo.Amount.PayerTotal), msg)
|
||||
merchantCallback, _ := json.Marshal(res)
|
||||
// 记录日志
|
||||
go func() {
|
||||
payCallback, _ := json.Marshal(CallBackInfo)
|
||||
payParam := "{}"
|
||||
status := common.THIRD_ORDER_LOG_STATUS_SUCCESS
|
||||
SaveLog(int64(orderId), common.THIRD_ORDER_TYPE_CALL_BACK, string(payCallback), payParam, "{}", status)
|
||||
}()
|
||||
|
||||
if res.ErrCode != errorcode.Success {
|
||||
logger.Error(context.Background(), "WxPayCallBack 发生错误", fmt.Sprintf("回调时,下游处理订单失败,返回数据为:%s", string(merchantCallback)))
|
||||
return errors.New("回调时,下游处理订单失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WxOrderQuery 查询微信订单
|
||||
func WxOrderQuery(ctx context.Context, wxConfig WxPay, orderNo string) (PayOrderQueryInfo, error) {
|
||||
// 初始化微信客户端
|
||||
wxClient, err := InitClient(wxConfig)
|
||||
if err != nil {
|
||||
return PayOrderQueryInfo{}, err
|
||||
}
|
||||
|
||||
wxRsp, err := wxClient.V3TransactionQueryOrder(ctx, payCommon.ORDER_NO_TYPE_ORDER_NO, orderNo)
|
||||
if err != nil {
|
||||
return PayOrderQueryInfo{}, err
|
||||
}
|
||||
if wxRsp.Code != wechat.Success {
|
||||
return PayOrderQueryInfo{}, errors.New(fmt.Sprintf("查询订单接口错误,错误状态码:%d, 错误信息:%s", wxRsp.Code, wxRsp.Error))
|
||||
}
|
||||
|
||||
// 映射交易状态
|
||||
tradeState := ""
|
||||
switch wxRsp.Response.TradeState {
|
||||
case "SUCCESS":
|
||||
tradeState = "SUCCESS"
|
||||
case "REFUND":
|
||||
tradeState = "REFUND"
|
||||
case "NOTPAY":
|
||||
tradeState = "NOTPAY"
|
||||
case "CLOSED":
|
||||
tradeState = "CLOSED"
|
||||
}
|
||||
amountTotal := wxRsp.Response.Amount.Total
|
||||
payerTotal := wxRsp.Response.Amount.PayerTotal
|
||||
|
||||
outTradeNo, _ := strconv.Atoi(wxRsp.Response.OutTradeNo)
|
||||
return PayOrderQueryInfo{
|
||||
AppId: wxRsp.Response.Appid,
|
||||
OutTradeNo: int64(outTradeNo),
|
||||
TransactionId: wxRsp.Response.TransactionId,
|
||||
TradeState: tradeState,
|
||||
TradeStateDesc: wxRsp.Response.TradeStateDesc,
|
||||
SuccessTime: wxRsp.Response.SuccessTime,
|
||||
AmountTotal: int64(amountTotal),
|
||||
PayerTotal: int64(payerTotal),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WxOrderRefund 微信退款申请
|
||||
func WxOrderRefund(ctx context.Context, orderRefundRequest OrderRefundRequest) (OrderRefundInfo, error) {
|
||||
// 初始化微信客户端
|
||||
wxClient, err := InitClient(orderRefundRequest.Wx)
|
||||
if err != nil {
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
|
||||
// 初始化 BodyMap
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("out_trade_no", strconv.FormatInt(orderRefundRequest.OrderId, 10)).
|
||||
Set("sign_type", "MD5").
|
||||
// 必填 退款订单号(程序员定义的)
|
||||
Set("out_refund_no", strconv.FormatInt(orderRefundRequest.RefundOrderId, 10)).
|
||||
// 选填 退款描述
|
||||
Set("reason", orderRefundRequest.RefundReason).
|
||||
SetBodyMap("amount", func(bm gopay.BodyMap) {
|
||||
// 退款金额:单位是分
|
||||
bm.Set("refund", orderRefundRequest.RefundAmount). //实际退款金额
|
||||
Set("total", orderRefundRequest.RefundAmount). // 折扣前总金额(不是实际退款数)
|
||||
Set("currency", "CNY")
|
||||
})
|
||||
// body:参数Body
|
||||
refund, err := wxClient.V3Refund(ctx, bm)
|
||||
if err != nil {
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
|
||||
// 将非正常退款异常记录
|
||||
if refund.Code != wechat.Success {
|
||||
logger.Error(ctx, "WxOrderRefund 发生错误", fmt.Sprintf("申请退款接口失败,错误状态码:%d, 错误信息:%s", refund.Code, refund.Error))
|
||||
// 这里时对非正常退款的一些处理message,我们将code统一使用自定义的,然后把message抛出去
|
||||
return OrderRefundInfo{}, errors.New(fmt.Sprintf("申请退款接口失败,错误状态码:%d, 错误信息:%s", refund.Code, refund.Error))
|
||||
}
|
||||
|
||||
outTradeNo, _ := strconv.Atoi(refund.Response.OutTradeNo)
|
||||
outRefundNo, _ := strconv.Atoi(refund.Response.OutRefundNo)
|
||||
refundStatus := payCommon.PAY_REFUND_STATU_COMMON
|
||||
switch refund.Response.Status {
|
||||
case "SUCCESS":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_SUCCESS
|
||||
case "CLOSED":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_FAIL
|
||||
case "PROCESSING":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_ING
|
||||
case "ABNORMAL":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_FAIL
|
||||
}
|
||||
return OrderRefundInfo{
|
||||
OutTradeNo: int64(outTradeNo),
|
||||
TransactionId: refund.Response.TransactionId,
|
||||
RefundFee: int64(refund.Response.Amount.PayerRefund),
|
||||
RefundOrderId: int64(outRefundNo),
|
||||
RefundStatus: refundStatus,
|
||||
RefundSuccessTime: refund.Response.SuccessTime,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WxOrderRefundQuery 微信订单退款查询
|
||||
func WxOrderRefundQuery(ctx context.Context, orderRefundQueryRequest OrderRefundQueryRequest) (OrderRefundInfo, error) {
|
||||
// 初始化微信客户端
|
||||
wxClient, err := InitClient(orderRefundQueryRequest.Wx)
|
||||
if err != nil {
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
|
||||
wxRsp, err := wxClient.V3RefundQuery(ctx, strconv.FormatInt(orderRefundQueryRequest.RefundOrderId, 10), nil)
|
||||
if err != nil {
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
if wxRsp.Code != wechat.Success {
|
||||
return OrderRefundInfo{}, errors.New(fmt.Sprintf("查询订单接口错误,错误状态码:%d, 错误信息:%s", wxRsp.Code, wxRsp.Error))
|
||||
}
|
||||
outTradeNo, _ := strconv.Atoi(wxRsp.Response.OutTradeNo)
|
||||
outRefundNo, _ := strconv.Atoi(wxRsp.Response.OutRefundNo)
|
||||
refundStatus := payCommon.PAY_REFUND_STATU_COMMON
|
||||
switch wxRsp.Response.Status {
|
||||
case "SUCCESS":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_SUCCESS
|
||||
case "CLOSED":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_FAIL
|
||||
case "PROCESSING":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_ING
|
||||
case "ABNORMAL":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_FAIL
|
||||
}
|
||||
return OrderRefundInfo{
|
||||
OutTradeNo: int64(outTradeNo),
|
||||
TransactionId: wxRsp.Response.TransactionId,
|
||||
RefundFee: int64(wxRsp.Response.Amount.PayerRefund),
|
||||
RefundOrderId: int64(outRefundNo),
|
||||
RefundStatus: refundStatus,
|
||||
RefundSuccessTime: wxRsp.Response.SuccessTime,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WxCloseOrder 微信订单关闭
|
||||
func WxCloseOrder(ctx context.Context, orderCloseRequest OrderCloseRequest) (OrderCloseInfo, error) {
|
||||
// 初始化微信客户端
|
||||
wxClient, err := InitClient(orderCloseRequest.Wx)
|
||||
if err != nil {
|
||||
return OrderCloseInfo{}, err
|
||||
}
|
||||
|
||||
wxRsp, err := wxClient.V3TransactionCloseOrder(ctx, strconv.FormatInt(orderCloseRequest.OrderId, 10))
|
||||
if err != nil {
|
||||
return OrderCloseInfo{}, err
|
||||
}
|
||||
if wxRsp.Code != wechat.Success {
|
||||
logger.Error(ctx, "WxCloseOrder 发生错误", fmt.Sprintf("查询订单接口错误,错误状态码:%d, 错误信息:%s", wxRsp.Code, wxRsp.Error))
|
||||
return OrderCloseInfo{}, errors.New(fmt.Sprintf("查询订单接口错误,错误状态码:%d, 错误信息:%s", wxRsp.Code, wxRsp.Error))
|
||||
}
|
||||
return OrderCloseInfo{
|
||||
OutTradeNo: orderCloseRequest.OrderId,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package aes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const (
|
||||
TestKey = "ROK0nAaxcsI0KRCy8VJgLlnlfjWYAOHk"
|
||||
)
|
||||
|
||||
// 加密函数
|
||||
func Encrypt(plaintext, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 加密后的数据会比原文长,因为需要添加一些填充字节
|
||||
// PKCS#7填充
|
||||
plaintext = pkcs7Padding(plaintext, block.BlockSize())
|
||||
|
||||
// 创建一个cipher.BlockMode,这里使用CBC模式
|
||||
// 需要一个iv(初始化向量),它的长度和Block的块大小相同
|
||||
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
|
||||
|
||||
// 返回的密文包括iv和加密后的数据
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// 解密函数
|
||||
func Decrypt(ciphertext, key []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
return nil, fmt.Errorf("ciphertext too short")
|
||||
}
|
||||
|
||||
// 提取iv
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
ciphertext = ciphertext[aes.BlockSize:]
|
||||
|
||||
// 创建一个cipher.BlockMode
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
|
||||
// 解密
|
||||
mode.CryptBlocks(ciphertext, ciphertext)
|
||||
|
||||
// 去除PKCS#7填充
|
||||
plaintext, err := pkcs7Unpadding(ciphertext, block.BlockSize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// PKCS#7填充
|
||||
func pkcs7Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
// 去除PKCS#7填充
|
||||
func pkcs7Unpadding(ciphertext []byte, blockSize int) ([]byte, error) {
|
||||
length := len(ciphertext)
|
||||
unpadding := int(ciphertext[length-1])
|
||||
if unpadding > blockSize || unpadding == 0 {
|
||||
return nil, fmt.Errorf("invalid padding")
|
||||
}
|
||||
return ciphertext[:(length - unpadding)], nil
|
||||
}
|
||||
|
||||
func GenerateRandomStringCrypto(length int) (string, error) {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
var bytes = make([]byte, length)
|
||||
for i := range bytes {
|
||||
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bytes[i] = charset[num.Int64()]
|
||||
}
|
||||
return string(bytes), nil
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package aes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateKey(t *testing.T) {
|
||||
key, _ := GenerateRandomStringCrypto(32)
|
||||
fmt.Printf(key)
|
||||
}
|
||||
|
||||
func TestAesEncrypt(t *testing.T) {
|
||||
|
||||
fmt.Printf("%s\n", encrypt())
|
||||
}
|
||||
|
||||
func TestAesDecrypt(t *testing.T) {
|
||||
data := "dk9trGQn2kZyE0rmfYglxwNmr7gc0DGFWvnPDVpLHfzwPiaWKkr+ZffKu0wj9/DQurIgjrQZIW8uV5/e+jxzBE6+5YZuKcT9+5xZSv6ieiXB7WUrKKnjxX/bHEaWgfoa0eDqEBhGth+mgql7qWFZLmuXpoKuAc0FPhdHTiynAttqjNMU4rMeXq52yJLuXrKHGlavhd9DETNDrhPFzyIAw7XjoMfGtBIFkXyDK5X+AKGkRvMJ8KfXR3lk9sSzTyGKRK/S"
|
||||
|
||||
res, err := Decrypt([]byte(data), []byte(TestKey))
|
||||
fmt.Println(string(res), err)
|
||||
}
|
||||
|
||||
func encrypt() string {
|
||||
data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}"
|
||||
|
||||
en, err := Encrypt([]byte(data), []byte(TestKey))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return string(en)
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
package rsa
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// parseRSAPublicKeyFromPEM 解析PEM编码的RSA公钥
|
||||
func parseRSAPublicKeyFromPEM(pemData []byte) (*rsa.PublicKey, error) {
|
||||
block, _ := pem.Decode(pemData)
|
||||
if block == nil || block.Type != "PUBLIC KEY" {
|
||||
return nil, fmt.Errorf("failed to parse PEM block containing the RSA public key")
|
||||
}
|
||||
|
||||
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch pub := pub.(type) {
|
||||
case *rsa.PublicKey:
|
||||
return pub, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown public key type in PKIX wrapping")
|
||||
}
|
||||
}
|
||||
|
||||
// encrypt 使用RSA公钥加密数据
|
||||
func Encrypt(publicKeyPEM string, plaintext string) ([]byte, error) {
|
||||
var encryptedData []byte
|
||||
// 将PEM编码的公钥转换为[]byte
|
||||
pemData := []byte(publicKeyPEM)
|
||||
|
||||
// 解析PEM数据以获取公钥
|
||||
pubKey, err := parseRSAPublicKeyFromPEM(pemData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hash := sha256.New()
|
||||
maxBlockSize := pubKey.Size() - 2*hash.Size() - 2
|
||||
// 创建用于加密的随机填充
|
||||
label := []byte("") // OAEP标签,对于某些情况可能是非空的
|
||||
for len(plaintext) > 0 {
|
||||
blockSize := maxBlockSize
|
||||
if len(plaintext) < maxBlockSize {
|
||||
blockSize = len(plaintext)
|
||||
}
|
||||
block := plaintext[:blockSize]
|
||||
encryptedBlock, err := rsa.EncryptOAEP(hash, rand.Reader, pubKey, []byte(block), label)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encryptedData = append(encryptedData, encryptedBlock...)
|
||||
plaintext = plaintext[blockSize:]
|
||||
}
|
||||
return encryptedData, nil
|
||||
}
|
||||
|
||||
// parseRSAPrivateKeyFromPEM 解析PEM编码的RSA私钥
|
||||
func parseRSAPrivateKeyFromPEM(pemData []byte) (*rsa.PrivateKey, error) {
|
||||
block, _ := pem.Decode(pemData)
|
||||
if block == nil || block.Type != "RSA PRIVATE KEY" {
|
||||
return nil, fmt.Errorf("failed to parse PEM block containing the RSA private key")
|
||||
}
|
||||
|
||||
// 尝试使用PKCS#1 v1.5
|
||||
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
// 如果失败,尝试使用PKCS#8
|
||||
privInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch k := privInterface.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
priv = k
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown private key type in PKCS#8 wrapping")
|
||||
}
|
||||
}
|
||||
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
// decrypt 使用RSA私钥解密数据
|
||||
func Decrypt(privateKeyPEM string, encryptedDataBase64 string) ([]byte, error) {
|
||||
var decryptedData []byte
|
||||
// 将PEM编码的私钥转换为[]byte
|
||||
pemData := []byte(privateKeyPEM)
|
||||
// 解析PEM数据以获取私钥
|
||||
privKey, err := parseRSAPrivateKeyFromPEM(pemData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keySize := privKey.PublicKey.Size()
|
||||
label := []byte("") // OAEP标签,对于某些情况可能是非空的
|
||||
hash := sha256.New()
|
||||
// 将Base64编码的加密数据解码为字节切片
|
||||
encryptedData, err := base64.StdEncoding.DecodeString(encryptedDataBase64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for len(encryptedData) > 0 {
|
||||
block := encryptedData[:keySize]
|
||||
// 这里假设使用的是OAEP填充和SHA-256哈希函数
|
||||
decryptedBlock, err := rsa.DecryptOAEP(hash, rand.Reader, privKey, block, label)
|
||||
if err != nil {
|
||||
//// 如果失败,可以尝试使用PKCS#1 v1.5填充
|
||||
decryptedBlock, err = rsa.DecryptPKCS1v15(rand.Reader, privKey, encryptedData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
decryptedData = append(decryptedData, decryptedBlock...)
|
||||
encryptedData = encryptedData[keySize:]
|
||||
}
|
||||
return decryptedData, nil
|
||||
}
|
||||
|
||||
// 生成密钥对
|
||||
func GenerateKey() (string, string, error) {
|
||||
// 生成私钥
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
// 导出私钥PKCS#1格式
|
||||
privKey := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||
// 将私钥转换为PEM编码
|
||||
var privBlock = &pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: privKey,
|
||||
}
|
||||
privPem := pem.EncodeToMemory(privBlock)
|
||||
// 导出公钥
|
||||
pubKey := &privateKey.PublicKey
|
||||
derPkix, err := x509.MarshalPKIXPublicKey(pubKey)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
// 将公钥转换为PEM编码
|
||||
var pubBlock = &pem.Block{
|
||||
Type: "PUBLIC KEY",
|
||||
Bytes: derPkix,
|
||||
}
|
||||
pubPem := pem.EncodeToMemory(pubBlock)
|
||||
pri := strings.Replace(string(privPem), "-----BEGIN RSA PRIVATE KEY-----\n", "", -1)
|
||||
pri = strings.Replace(pri, "\n-----END RSA PRIVATE KEY-----\n", "", -1)
|
||||
pub := strings.Replace(string(pubPem), "-----BEGIN PUBLIC KEY-----\n", "", -1)
|
||||
pub = strings.Replace(pub, "\n-----END PUBLIC KEY-----\n", "", -1)
|
||||
return pub, pri, nil
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package rsa
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/utils/encrypt/aes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
PRI = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmjK6SPkrP03ssex5Dxn4KZeVm9rQoJMslru13GNgoGKJAq13xwUGl6lpGlhzM9IMzg0ldOO2a0SQPPjc0fLrDjIgHPfIT6H1hDGkZdPaF4D0OfiHGzlLwXq7FyyyGc2JXILsniMBXcCxNFhbW0jAaJyYrBJb3q84a5y5AtK3IC+eDV6Bj2J4HlQVGKgW9u2ic6Jxl23sacXY6iifi+KEuoXNCJrmYlgRWTaQovLmTCLkErkzxzG9DFRDWGoz25LthDPqcCSUmWEbJ+obwIGB4r2WCbFXvaeVBQORlyVRyNUvYMItjHBQIKinDWZ6y8KzA0YKOoxEfr0KfE8Uk4PQBAgMBAAECggEABTAX0PzelN4uyvTT0sMi/R0YRKPgepP40vtBsNvF10E7Lp4ClAupHpYFSrJq178xu1/2dVBXEGM9hw8GUQd7RCjuD3cFwcp/EKU+Zy6uQ38iZRTskEDa3bC+q3EXzuFXDxqOfIhai262UTlkATw0sjUwJRdkbMxoeWHkSNuH7UBVddxFL8Bq1DKaPzRCqQ8zlkMZHy8Xbf2b8rFoi1oPBoPjHyxCo33zcnSg5xntIoA5pkD6x4z5cAnU55aBoYUiRv7jmG+MVp1jpDvAmJLfUayVZNakgX1r74bMPsl9kpA7dVdgOlWrIkbJE1plVXXswBb8QKN0/Yx2vv/YASSi0QKBgQDaO9BkRjvht/lrsQEur1wXf5ITnsVWsqlUhYQKGHihzOj7e0rGO9QICM4eQZH9ssHfxEXhmEoFdkaqo3Fo47NI+yinpWm+KruwrRFkCGejlKZ4bhn9zWPb8L1qJbN4UD1c5jUNk1B0EEdnLRFg0/O7xm602bGilvY5x2nf0v95+QKBgQDDXyiiGNV7GO4h8OQYJwq0IqenPyIanRgYI3rw//tg147mhWcxT6ms6dMUh9nEXEFali2J1En+aVvx1Xn47CuGrRmZOLaGkw9ESFA/4ngYdea+xgttbKMXm0QwIwvATq2jxxrYEKmnr/+EUUWzIWioM1zQffAhVlkLFVnImquMSQKBgDe7qNfC/A4ELwWqubOTg0BZCxRJqvoePJJiWrs9Tql7rFB1Rz5jDx5SKVmew0r4OP0Nog8gFl9YumlfvlncNPBBfDt8SgoP3ckcGeHjJ5ymHPGKpMaliogj7ivKnw/t5g3wmMHzyksp0SJvZw3Ec22UGrfDFNOCHDXbUJWhzC75AoGBALbM6rAAnH65LNcFFeajYRh69HNAVyCfrFOpnvawDPzntAVs/MjeyNvJTH8BPXjE+UFREvrLbxBkdGsqWx3VnEQ+4pzCu8XfA4HYR33+4G/CoUwO8dJIu7DyzjJcGDqvYzjCqxNPQ+5qdqHPiW+56rq2lDlgHLaUnGwKZh+U2L5BAoGAeogtSQbnZaLQofSGcUOol2fyG24NU1JK3My+N1ypkSpD+y1KiFQeM5kg7UcJB6LBKZ/lRCKcjEMaxMyj57ETMkbRVKBLvsIL5QYolJLIHYqBul0AeFJ4K51SKK2Xk5rFvyuJKkJBux26WodtCXTnEzP1KRZGlSxJeN/V1yXjSEU="
|
||||
|
||||
PUB = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApoyukj5Kz9N7LHseQ8Z+CmXlZva0KCTLJa7tdxjYKBiiQKtd8cFBpepaRpYczPSDM4NJXTjtmtEkDz43NHy6w4yIBz3yE+h9YQxpGXT2heA9Dn4hxs5S8F6uxcsshnNiVyC7J4jAV3AsTRYW1tIwGicmKwSW96vOGucuQLStyAvng1egY9ieB5UFRioFvbtonOicZdt7GnF2Ooon4vihLqFzQia5mJYEVk2kKLy5kwi5BK5M8cxvQxUQ1hqM9uS7YQz6nAklJlhGyfqG8CBgeK9lgmxV72nlQUDkZclUcjVL2DCLYxwUCCopw1mesvCswNGCjqMRH69CnxPFJOD0AQIDAQAB"
|
||||
)
|
||||
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
fmt.Printf("%s\n", encrypt())
|
||||
}
|
||||
|
||||
func TestRsaDecrypt(t *testing.T) {
|
||||
data := "pPnAPy7v2SY9Fu0LFcQH8UBA6VQ2FCfSg3nRZdMXS7mWjBwlacKHuFnh9UhobL7mxnmMyZPP100bpjCg2kvcfOpOp3ci85p+OYWINt4Fh3qgEOTG5FUyziaagGLm882t/I36KsDTVvbMZvC5sg4gZ9JQ5yAR+nuJfr0IxI0se/iD5luV1rms1kZHggd30iXdZtbkbX7xJ4xtnIiJmZU7kL+Xmvv1rDdPLxbol65QfnM1me1IHkXJapqSBnhEEmFQyBx31vp1ccNjkza8ZWbvTPCngc1k4kvlm6lKfwsG4hMuSdXUzveDm+Oo8StAKnyVoerJ202n7Vfx1XhehineQT0TPD7bO0HCEsDXXYEWwvcax8VdzYvHk7qSbH6e154qCr4LgDRSHKwAAExinTrzxx2rtSimieBLaEpDL2v5ch45HnhjRhWTRmM61W1g6sdHaVX1mQxaXvrT4v+h+f4TbIV4r4qeGJ6rXG+yKRoYseLzyGgystoOny9P0UH15W8rWPytV2eioWT7i3Cglg04BWP9mst67LQXeFH4CA6CkwVV2w9nCHrzxX2ouYSQELUEkTlIMry2AlkZubUnupGJLmLLUyZj7pM/6cLjyAgm02/gRc4wwf7JBBq/ipmKXpkhHXWLtQDWJEZTT+ug2v9EXy5dgPNPe8ZI0MILAeipjIc="
|
||||
privateKeyPEM := `-----BEGIN RSA PRIVATE KEY-----
|
||||
` + PRI + `
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
res, err := Decrypt(privateKeyPEM, data)
|
||||
fmt.Println(string(res), err)
|
||||
}
|
||||
|
||||
func encrypt() string {
|
||||
data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"refundOutTreadNo001\",\"amount\":1,\"desc\":\"退款\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643,\"refund_out_trade_no\":\"asdadasdas\"}"
|
||||
pub := `-----BEGIN PUBLIC KEY-----
|
||||
` + PUB + `
|
||||
-----END PUBLIC KEY-----`
|
||||
en, err := Encrypt(pub, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(en)
|
||||
}
|
||||
|
||||
func encryptWithAes() string {
|
||||
data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"refundOutTreadNo001\",\"amount\":1,\"desc\":\"退款\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643,\"refund_out_trade_no\":\"asdadasdas\"}"
|
||||
aes.Encrypt([]byte(data), []byte(aes.TestKey))
|
||||
|
||||
dataJson := base64.StdEncoding.EncodeToString([]byte(data))
|
||||
pub := `-----BEGIN PUBLIC KEY-----
|
||||
` + PUB + `
|
||||
-----END PUBLIC KEY-----`
|
||||
en, err := Encrypt(pub, dataJson)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(en)
|
||||
}
|
||||
|
||||
// 测试生成密钥对
|
||||
func TestGenerateRSAKey(t *testing.T) {
|
||||
pub, pri, _ := GenerateKey()
|
||||
|
||||
fmt.Println("pub:", pub, "\n", "pri:", pri)
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"PaymentCenter/config"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
|
@ -16,12 +15,21 @@ func GenerateSM2Key() (PublicKey string, PrivateKey string, err error) {
|
|||
// 生成私钥、公钥
|
||||
privKey, err := sm2.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
fmt.Println("生成密钥对失败:", err)
|
||||
|
||||
return "", "", err
|
||||
}
|
||||
return PublicKeyToString(&privKey.PublicKey), PrivateKeyToString(privKey), nil
|
||||
}
|
||||
|
||||
// GenerateKey 生成密钥对
|
||||
func GenerateKey() (string, string) {
|
||||
pri, _ := sm2.GenerateKey(rand.Reader)
|
||||
hexPri := pri.D.Text(16)
|
||||
// 获取公钥
|
||||
publicKeyHex := PublicKeyToString(&pri.PublicKey)
|
||||
return strings.ToUpper(hexPri), publicKeyHex
|
||||
}
|
||||
|
||||
// PublicKeyToString 公钥sm2.PublicKey转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
|
||||
func PublicKeyToString(publicKey *sm2.PublicKey) string {
|
||||
xBytes := publicKey.X.Bytes()
|
||||
|
@ -48,27 +56,27 @@ func PrivateKeyToString(privateKey *sm2.PrivateKey) string {
|
|||
return strings.ToUpper(hex.EncodeToString(privateKey.D.Bytes()))
|
||||
}
|
||||
|
||||
func SM2Decrypt(cipherText string) (string, error) {
|
||||
func SM2Decrypt(cipherText, publicKey string, privateKey string) (string, error) {
|
||||
if cipherText == "" {
|
||||
return "", nil
|
||||
}
|
||||
decodedBytes, err := base64.StdEncoding.DecodeString(cipherText)
|
||||
if err != nil {
|
||||
fmt.Println("解码错误:", err)
|
||||
|
||||
return "", nil
|
||||
}
|
||||
decrypt, err := decryptLoc(config.GetConf().Sm2.PublicKey, config.GetConf().Sm2.PrivateKey, string(decodedBytes))
|
||||
decrypt, err := decryptLoc(publicKey, privateKey, string(decodedBytes))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return decrypt, nil
|
||||
}
|
||||
|
||||
func SM2Encrypt(cipherText string) (string, error) {
|
||||
func SM2Encrypt(cipherText string, privateKey string) (string, error) {
|
||||
if cipherText == "" {
|
||||
return "", nil
|
||||
}
|
||||
decrypt, err := encryptLoc(config.GetConf().Sm2.PublicKey, cipherText)
|
||||
decrypt, err := encryptLoc(privateKey, cipherText)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -78,11 +86,11 @@ func SM2Encrypt(cipherText string) (string, error) {
|
|||
func encryptLoc(publicKeyStr, data string) (string, error) {
|
||||
publicKeyObj, err := StringToPublicKey(publicKeyStr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return "", err
|
||||
}
|
||||
decrypt, err := sm2.Encrypt(publicKeyObj, []byte(data), rand.Reader, sm2.C1C2C3)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return "", err
|
||||
}
|
||||
resultStr := hex.EncodeToString(decrypt)
|
||||
return base64.StdEncoding.EncodeToString([]byte(resultStr)), nil
|
||||
|
@ -103,7 +111,6 @@ func decryptLoc(publicKeyStr, privateKeyStr, cipherText string) (string, error)
|
|||
fmt.Println(err)
|
||||
}
|
||||
resultStr := string(decrypt)
|
||||
fmt.Println("解密后的字符串:", resultStr)
|
||||
return resultStr, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
SELF_PRI = "BD13D44C74422F80ADDF54AD2DE2888C4092AF6F61E41FABADA6C47F17574A41"
|
||||
|
||||
SELF_PUB = "04F26C6CDA5E58153999FDF3023259F16EDE0A556C39FCF4BC97C04A10A8A6CF1D52297B53DB4DD72FEEF8221394C8478E6424F4E84E4A6E2784C1A4A1C99F2DC2"
|
||||
)
|
||||
|
||||
func TestGenerateSM2KeyPair(t *testing.T) {
|
||||
// Generate a new SM2 key pair
|
||||
privateKey, publicKey := GenerateKey()
|
||||
|
||||
// Print the private and public keys
|
||||
fmt.Printf("Private Key: %s\n", privateKey)
|
||||
fmt.Printf("Public Key: %s\n", publicKey)
|
||||
|
||||
data := "{\"name\":\"张三\",\"sex\":1,\"is_human\":true}"
|
||||
en, err := SM2Encrypt(data, publicKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
decrypt, err := SM2Decrypt(en, publicKey, privateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Log(decrypt)
|
||||
|
||||
}
|
||||
|
||||
func TestSM2Encrypt(t *testing.T) {
|
||||
t.Log(encrypt())
|
||||
}
|
||||
|
||||
func TestSM2Decrypt(t *testing.T) {
|
||||
en := encrypt()
|
||||
decrypt, err := SM2Decrypt(en, SELF_PUB, SELF_PRI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Log(decrypt)
|
||||
}
|
||||
|
||||
func encrypt() string {
|
||||
data := "{\"order_no\":5476377146882523228,\"order_type\":1,\"out_tread_no\":\"asdadasdas\",\"amount\":1,\"desc\":\"abc\",\"status\":2,\"create_time\":\"2024-08-08 14:47:35\"}"
|
||||
en, err := SM2Encrypt(data, SELF_PUB)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return en
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
* 来源于 github.com/tjfoc/gmsm
|
||||
* 修改适配 邮储对接
|
|
@ -0,0 +1,219 @@
|
|||
package sm2
|
||||
|
||||
// reference to ecdsa
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"github.com/tjfoc/gmsm/sm3"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var (
|
||||
default_uid = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
|
||||
)
|
||||
|
||||
type PublicKey struct {
|
||||
elliptic.Curve
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
D *big.Int
|
||||
}
|
||||
|
||||
type sm2Signature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
func (priv *PrivateKey) Public() crypto.PublicKey {
|
||||
return &priv.PublicKey
|
||||
}
|
||||
|
||||
var errZeroParam = errors.New("zero parameter")
|
||||
var one = new(big.Int).SetInt64(1)
|
||||
var two = new(big.Int).SetInt64(2)
|
||||
|
||||
func (priv *PrivateKey) Sign(random io.Reader, msg []byte, signer crypto.SignerOpts) ([]byte, error) {
|
||||
r, s, err := Sm2Sign(priv, msg, nil, random)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asn1.Marshal(sm2Signature{r, s})
|
||||
}
|
||||
|
||||
func Sm2Sign(priv *PrivateKey, msg, uid []byte, random io.Reader) (r, s *big.Int, err error) {
|
||||
digest, err := priv.PublicKey.Sm3Digest(msg, uid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
e := new(big.Int).SetBytes(digest)
|
||||
c := priv.PublicKey.Curve
|
||||
N := c.Params().N
|
||||
if N.Sign() == 0 {
|
||||
return nil, nil, errZeroParam
|
||||
}
|
||||
var k *big.Int
|
||||
for { // 调整算法细节以实现SM2
|
||||
for {
|
||||
k, err = randFieldElement(c, random)
|
||||
if err != nil {
|
||||
r = nil
|
||||
return
|
||||
}
|
||||
r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
|
||||
r.Add(r, e)
|
||||
r.Mod(r, N)
|
||||
if r.Sign() != 0 {
|
||||
if t := new(big.Int).Add(r, k); t.Cmp(N) != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
rD := new(big.Int).Mul(priv.D, r)
|
||||
s = new(big.Int).Sub(k, rD)
|
||||
d1 := new(big.Int).Add(priv.D, one)
|
||||
d1Inv := new(big.Int).ModInverse(d1, N)
|
||||
s.Mul(s, d1Inv)
|
||||
s.Mod(s, N)
|
||||
if s.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (pub *PublicKey) Sm3Digest(msg, uid []byte) ([]byte, error) {
|
||||
if len(uid) == 0 {
|
||||
uid = default_uid
|
||||
}
|
||||
|
||||
za, err := getZ(pub, uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e, err := msgHash(za, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
func Sm2Verify(pub *PublicKey, msg, uid []byte, r, s *big.Int) bool {
|
||||
c := pub.Curve
|
||||
N := c.Params().N
|
||||
one := new(big.Int).SetInt64(1)
|
||||
if r.Cmp(one) < 0 || s.Cmp(one) < 0 {
|
||||
return false
|
||||
}
|
||||
if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
|
||||
return false
|
||||
}
|
||||
if len(uid) == 0 {
|
||||
uid = default_uid
|
||||
}
|
||||
za, err := getZ(pub, uid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
e, err := msgHash(za, msg)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
t := new(big.Int).Add(r, s)
|
||||
t.Mod(t, N)
|
||||
if t.Sign() == 0 {
|
||||
return false
|
||||
}
|
||||
var x *big.Int
|
||||
x1, y1 := c.ScalarBaseMult(s.Bytes())
|
||||
x2, y2 := c.ScalarMult(pub.X, pub.Y, t.Bytes())
|
||||
x, _ = c.Add(x1, y1, x2, y2)
|
||||
|
||||
x.Add(x, e)
|
||||
x.Mod(x, N)
|
||||
return x.Cmp(r) == 0
|
||||
}
|
||||
|
||||
func msgHash(za, msg []byte) (*big.Int, error) {
|
||||
e := sm3.New()
|
||||
e.Write(za)
|
||||
e.Write(msg)
|
||||
return new(big.Int).SetBytes(e.Sum(nil)[:32]), nil
|
||||
}
|
||||
|
||||
func bigIntToByte(n *big.Int) []byte {
|
||||
byteArray := n.Bytes()
|
||||
// If the most significant byte's most significant bit is set,
|
||||
// prepend a 0 byte to the slice to avoid being interpreted as a negative number.
|
||||
if (byteArray[0] & 0x80) != 0 {
|
||||
byteArray = append([]byte{0}, byteArray...)
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
||||
func getZ(pub *PublicKey, uid []byte) ([]byte, error) {
|
||||
z := sm3.New()
|
||||
uidLen := len(uid) * 8
|
||||
entla := []byte{byte(uidLen >> 8), byte(uidLen & 255)}
|
||||
z.Write(entla)
|
||||
z.Write(uid)
|
||||
|
||||
// a 先写死,原来的没有暴露
|
||||
z.Write(bigIntToByte(sm2P256ToBig(&sm2P256.a)))
|
||||
z.Write(bigIntToByte(sm2P256.B))
|
||||
z.Write(bigIntToByte(sm2P256.Gx))
|
||||
z.Write(bigIntToByte(sm2P256.Gy))
|
||||
|
||||
z.Write(bigIntToByte(pub.X))
|
||||
z.Write(bigIntToByte(pub.Y))
|
||||
return z.Sum(nil), nil
|
||||
}
|
||||
|
||||
func randFieldElement(c elliptic.Curve, random io.Reader) (k *big.Int, err error) {
|
||||
if random == nil {
|
||||
random = rand.Reader //If there is no external trusted random source,please use rand.Reader to instead of it.
|
||||
}
|
||||
params := c.Params()
|
||||
b := make([]byte, params.BitSize/8+8)
|
||||
_, err = io.ReadFull(random, b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
k = new(big.Int).SetBytes(b)
|
||||
n := new(big.Int).Sub(params.N, one)
|
||||
k.Mod(k, n)
|
||||
k.Add(k, one)
|
||||
return
|
||||
}
|
||||
|
||||
func GenerateKey(random io.Reader) (*PrivateKey, error) {
|
||||
c := P256Sm2()
|
||||
if random == nil {
|
||||
random = rand.Reader //If there is no external trusted random source,please use rand.Reader to instead of it.
|
||||
}
|
||||
params := c.Params()
|
||||
b := make([]byte, params.BitSize/8+8)
|
||||
_, err := io.ReadFull(random, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k := new(big.Int).SetBytes(b)
|
||||
n := new(big.Int).Sub(params.N, two)
|
||||
k.Mod(k, n)
|
||||
k.Add(k, one)
|
||||
priv := new(PrivateKey)
|
||||
priv.PublicKey.Curve = c
|
||||
priv.D = k
|
||||
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
|
||||
|
||||
return priv, nil
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package sm2
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func ReadPrivateKeyFromHex(Dhex string) (*PrivateKey, error) {
|
||||
c := P256Sm2()
|
||||
d, err := hex.DecodeString(Dhex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k := new(big.Int).SetBytes(d)
|
||||
params := c.Params()
|
||||
one := new(big.Int).SetInt64(1)
|
||||
n := new(big.Int).Sub(params.N, one)
|
||||
if k.Cmp(n) >= 0 {
|
||||
return nil, errors.New("privateKey's D is overflow.")
|
||||
}
|
||||
priv := new(PrivateKey)
|
||||
priv.PublicKey.Curve = c
|
||||
priv.D = k
|
||||
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
func ReadPublicKeyFromHex(Qhex string) (*PublicKey, error) {
|
||||
q, err := hex.DecodeString(Qhex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(q) == 65 && q[0] == byte(0x04) {
|
||||
q = q[1:]
|
||||
}
|
||||
if len(q) != 64 {
|
||||
return nil, errors.New("publicKey is not uncompressed.")
|
||||
}
|
||||
pub := new(PublicKey)
|
||||
pub.Curve = P256Sm2()
|
||||
pub.X = new(big.Int).SetBytes(q[:32])
|
||||
pub.Y = new(big.Int).SetBytes(q[32:])
|
||||
return pub, nil
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/utils/encrypt/sm4/internal/sm2"
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
zzsm2 "github.com/ZZMarquis/gm/sm2"
|
||||
"github.com/tjfoc/gmsm/sm3"
|
||||
"github.com/tjfoc/gmsm/x509"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func Sm2Decrypt(privateKey *sm2.PrivateKey, encryptData []byte) ([]byte, error) {
|
||||
C1Byte := make([]byte, 65)
|
||||
copy(C1Byte, encryptData[:65])
|
||||
x, y := elliptic.Unmarshal(privateKey.Curve, C1Byte)
|
||||
dBC1X, dBC1Y := privateKey.Curve.ScalarMult(x, y, bigIntToByte(privateKey.D))
|
||||
dBC1Bytes := elliptic.Marshal(privateKey.Curve, dBC1X, dBC1Y)
|
||||
|
||||
kLen := len(encryptData) - 65 - 32
|
||||
t, err := kdf(dBC1Bytes, kLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
M := make([]byte, kLen)
|
||||
for i := 0; i < kLen; i++ {
|
||||
M[i] = encryptData[65+i] ^ t[i]
|
||||
}
|
||||
|
||||
C3 := make([]byte, 32)
|
||||
copy(C3, encryptData[len(encryptData)-32:])
|
||||
u := calculateHash(dBC1X, M, dBC1Y)
|
||||
|
||||
if bytes.Compare(u, C3) == 0 {
|
||||
return M, nil
|
||||
} else {
|
||||
return nil, errors.New("解密失败")
|
||||
}
|
||||
}
|
||||
|
||||
func Sm2Encrypt(publicKey *sm2.PublicKey, m []byte) ([]byte, error) {
|
||||
kLen := len(m)
|
||||
var C1, t []byte
|
||||
var err error
|
||||
var kx, ky *big.Int
|
||||
for {
|
||||
k, _ := rand.Int(rand.Reader, publicKey.Params().N)
|
||||
C1x, C1y := zzsm2.GetSm2P256V1().ScalarBaseMult(bigIntToByte(k))
|
||||
// C1x, C1y := sm2.P256Sm2().ScalarBaseMult(bigIntToByte(k))
|
||||
C1 = elliptic.Marshal(publicKey.Curve, C1x, C1y)
|
||||
|
||||
kx, ky = publicKey.ScalarMult(publicKey.X, publicKey.Y, bigIntToByte(k))
|
||||
kpbBytes := elliptic.Marshal(publicKey, kx, ky)
|
||||
t, err = kdf(kpbBytes, kLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isAllZero(t) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
C2 := make([]byte, kLen)
|
||||
for i := 0; i < kLen; i++ {
|
||||
C2[i] = m[i] ^ t[i]
|
||||
}
|
||||
|
||||
C3 := calculateHash(kx, m, ky)
|
||||
|
||||
r := make([]byte, 0, len(C1)+len(C2)+len(C3))
|
||||
r = append(r, C1...)
|
||||
r = append(r, C2...)
|
||||
r = append(r, C3...)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func isAllZero(m []byte) bool {
|
||||
for i := 0; i < len(m); i++ {
|
||||
if m[i] != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func calculateHash(x *big.Int, M []byte, y *big.Int) []byte {
|
||||
digest := sm3.New()
|
||||
digest.Write(bigIntToByte(x))
|
||||
digest.Write(M)
|
||||
digest.Write(bigIntToByte(y))
|
||||
result := digest.Sum(nil)[:32]
|
||||
return result
|
||||
}
|
||||
|
||||
func bigIntToByte(n *big.Int) []byte {
|
||||
byteArray := n.Bytes()
|
||||
// If the most significant byte's most significant bit is set,
|
||||
// prepend a 0 byte to the slice to avoid being interpreted as a negative number.
|
||||
if (byteArray[0] & 0x80) != 0 {
|
||||
byteArray = append([]byte{0}, byteArray...)
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
||||
func kdf(Z []byte, klen int) ([]byte, error) {
|
||||
ct := 1
|
||||
end := (klen + 31) / 32
|
||||
result := make([]byte, 0)
|
||||
for i := 1; i <= end; i++ {
|
||||
b, err := sm3hash(Z, toByteArray(ct))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, b...)
|
||||
ct++
|
||||
}
|
||||
last, err := sm3hash(Z, toByteArray(ct))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if klen%32 == 0 {
|
||||
result = append(result, last...)
|
||||
} else {
|
||||
result = append(result, last[:klen%32]...)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func sm3hash(sources ...[]byte) ([]byte, error) {
|
||||
b, err := joinBytes(sources...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
md := make([]byte, 32)
|
||||
h := x509.SM3.New()
|
||||
h.Write(b)
|
||||
h.Sum(md[:0])
|
||||
return md, nil
|
||||
}
|
||||
|
||||
func joinBytes(params ...[]byte) ([]byte, error) {
|
||||
var buffer bytes.Buffer
|
||||
for i := 0; i < len(params); i++ {
|
||||
_, err := buffer.Write(params[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func toByteArray(i int) []byte {
|
||||
byteArray := []byte{
|
||||
byte(i >> 24),
|
||||
byte((i & 16777215) >> 16),
|
||||
byte((i & 65535) >> 8),
|
||||
byte(i & 255),
|
||||
}
|
||||
return byteArray
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GenerateSM4Key() []byte {
|
||||
str := "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890"
|
||||
buffer := make([]byte, 16)
|
||||
for i := 0; i < 16; i++ {
|
||||
nextInt, _ := rand.Int(rand.Reader, big.NewInt(int64(len(str))))
|
||||
buffer[i] = str[nextInt.Int64()]
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
func GenAccessToken(token string) string {
|
||||
if token != "" {
|
||||
return token
|
||||
}
|
||||
now := time.Now()
|
||||
return strings.ToUpper(Md5Hash(now.Format("2006A01B02CD15E04F05"), ""))
|
||||
}
|
||||
|
||||
func Md5Hash(password, salt string) string {
|
||||
m := md5.New()
|
||||
m.Write([]byte(salt + password))
|
||||
return hex.EncodeToString(m.Sum(nil))
|
||||
}
|
||||
|
||||
// GetSM4IV 获取SM4的IV
|
||||
func GetSM4IV() []byte {
|
||||
return []byte("UISwD9fW6cFh9SNS")
|
||||
}
|
||||
|
||||
func Padding(input []byte, mode int) []byte {
|
||||
if input == nil {
|
||||
return nil
|
||||
} else {
|
||||
var ret []byte
|
||||
if mode == 1 {
|
||||
p := 16 - len(input)%16
|
||||
ret = make([]byte, len(input)+p)
|
||||
copy(ret, input)
|
||||
|
||||
for i := 0; i < p; i++ {
|
||||
ret[len(input)+i] = byte(p)
|
||||
}
|
||||
} else {
|
||||
p := input[len(input)-1]
|
||||
ret = make([]byte, len(input)-int(p))
|
||||
copy(ret, input[:len(input)-int(p)])
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
package sm4
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/utils/encrypt/sm4/internal/sm2"
|
||||
"PaymentCenter/app/utils/encrypt/sm4/internal/util"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ZZMarquis/gm/sm4"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func checkInData(reqData map[string]string, key string) (string, error) {
|
||||
data, ok := reqData[key]
|
||||
if !ok {
|
||||
return "", errors.New("请求数据中不存在" + key)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func Sm4Decrypt(merchantId, privateKey, sopPublicKey, respJson string, isRequest bool) (string, error) {
|
||||
var reqData map[string]string
|
||||
err := json.Unmarshal([]byte(respJson), &reqData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
keys := [4]string{}
|
||||
if isRequest {
|
||||
keys = [4]string{"request", "signature", "encryptKey", "accessToken"}
|
||||
} else {
|
||||
keys = [4]string{"response", "signature", "encryptKey", "accessToken"}
|
||||
}
|
||||
var inEncryptKey, inAccessToken, inData, inSignature string
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
data, err := checkInData(reqData, keys[i])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch keys[i] {
|
||||
case "request", "response":
|
||||
inData = data
|
||||
case "signature":
|
||||
inSignature = data
|
||||
case "encryptKey":
|
||||
inEncryptKey = data
|
||||
case "accessToken":
|
||||
inAccessToken = data
|
||||
}
|
||||
}
|
||||
|
||||
checked := verify(fmt.Sprintf("%s%s%s", inData, inEncryptKey, inAccessToken), inSignature, sopPublicKey, merchantId)
|
||||
if !checked {
|
||||
return "", errors.New("签名验证失败")
|
||||
}
|
||||
|
||||
priKey, err := sm2.ReadPrivateKeyFromHex(privateKey)
|
||||
if err != nil {
|
||||
return "", errors.New("读取私钥失败")
|
||||
}
|
||||
hexEncryptKey, err := hex.DecodeString(inEncryptKey)
|
||||
if err != nil {
|
||||
return "", errors.New("解密sm4key失败")
|
||||
}
|
||||
sm4Key, err := util.Sm2Decrypt(priKey, hexEncryptKey)
|
||||
|
||||
request, _ := base64.StdEncoding.DecodeString(inData)
|
||||
|
||||
encryptedSm4Key, err := sm4.CBCDecrypt(sm4Key, util.GetSM4IV(), request)
|
||||
|
||||
return string(util.Padding(encryptedSm4Key, 0)), nil
|
||||
}
|
||||
|
||||
func Sm4Encrypt(merchantId, privateKey, sopPublicKey, inputJson, token string, isRequest bool) (string, error) {
|
||||
sm4Key := util.GenerateSM4Key()
|
||||
iv := util.GetSM4IV()
|
||||
tmp, err := sm4.CBCEncrypt(sm4Key, iv, util.Padding([]byte(inputJson), 1))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
responseMsg := base64.StdEncoding.EncodeToString(tmp)
|
||||
responseMsg = addNewline(responseMsg)
|
||||
|
||||
pubKey, err := sm2.ReadPublicKeyFromHex(sopPublicKey)
|
||||
if err != nil {
|
||||
return "", errors.New("读取私钥失败")
|
||||
}
|
||||
encryptKeyBytes, err := util.Sm2Encrypt(pubKey, sm4Key)
|
||||
encryptKey := strings.ToUpper(hex.EncodeToString(encryptKeyBytes))
|
||||
|
||||
accessToken := util.GenAccessToken(token)
|
||||
signContent := fmt.Sprintf("%s%s%s", responseMsg, encryptKey, accessToken)
|
||||
signature, err := sign(merchantId, privateKey, signContent)
|
||||
|
||||
var reqData map[string]string
|
||||
|
||||
if isRequest {
|
||||
reqData = map[string]string{
|
||||
"request": responseMsg,
|
||||
"signature": signature,
|
||||
"encryptKey": encryptKey,
|
||||
"accessToken": accessToken,
|
||||
}
|
||||
} else {
|
||||
reqData = map[string]string{
|
||||
"response": responseMsg,
|
||||
"signature": signature,
|
||||
"encryptKey": encryptKey,
|
||||
"accessToken": accessToken,
|
||||
}
|
||||
}
|
||||
|
||||
jsonStr, err := json.Marshal(reqData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(jsonStr), err
|
||||
}
|
||||
|
||||
// GenerateKey 生成密钥对
|
||||
func GenerateKey() (string, string) {
|
||||
pri, _ := sm2.GenerateKey(rand.Reader)
|
||||
hexPri := pri.D.Text(16)
|
||||
// 获取公钥
|
||||
publicKeyHex := publicKeyToString(&pri.PublicKey)
|
||||
return strings.ToUpper(hexPri), publicKeyHex
|
||||
}
|
||||
|
||||
// publicKeyToString 公钥sm2.PublicKey转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用)
|
||||
func publicKeyToString(publicKey *sm2.PublicKey) string {
|
||||
xBytes := publicKey.X.Bytes()
|
||||
yBytes := publicKey.Y.Bytes()
|
||||
|
||||
// 确保坐标字节切片长度相同
|
||||
byteLen := len(xBytes)
|
||||
if len(yBytes) > byteLen {
|
||||
byteLen = len(yBytes)
|
||||
}
|
||||
|
||||
// 为坐标补齐前导零
|
||||
xBytes = append(make([]byte, byteLen-len(xBytes)), xBytes...)
|
||||
yBytes = append(make([]byte, byteLen-len(yBytes)), yBytes...)
|
||||
|
||||
// 添加 "04" 前缀
|
||||
publicKeyBytes := append([]byte{0x04}, append(xBytes, yBytes...)...)
|
||||
|
||||
return strings.ToUpper(hex.EncodeToString(publicKeyBytes))
|
||||
}
|
||||
|
||||
func addNewline(str string) string {
|
||||
lineLength := 76
|
||||
var result strings.Builder
|
||||
for i := 0; i < len(str); i++ {
|
||||
if i > 0 && i%lineLength == 0 {
|
||||
result.WriteString("\r\n")
|
||||
}
|
||||
result.WriteByte(str[i])
|
||||
}
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func sign(merchantId string, privateKeyHex string, signContent string) (string, error) {
|
||||
privateKey, err := sm2.ReadPrivateKeyFromHex(privateKeyHex)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
r, s, err := sm2.Sm2Sign(privateKey, []byte(signContent), []byte(merchantId), rand.Reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return rSToSign(r, s), nil
|
||||
}
|
||||
|
||||
func verify(content string, signature string, publicKeyStr string, merchantId string) bool {
|
||||
pubKey, err := sm2.ReadPublicKeyFromHex(publicKeyStr)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("pubKeyBytes sm2 ReadPublicKeyFromHex err: %v", err))
|
||||
}
|
||||
r, s := signToRS(signature)
|
||||
return sm2.Sm2Verify(pubKey, []byte(content), []byte(merchantId), r, s)
|
||||
}
|
||||
|
||||
func signToRS(signStr string) (*big.Int, *big.Int) {
|
||||
signSub := strings.Split(signStr, "#")
|
||||
if len(signSub) != 2 {
|
||||
panic(fmt.Sprintf("err rs: %x", signSub))
|
||||
}
|
||||
r, _ := new(big.Int).SetString(signSub[0], 16)
|
||||
s, _ := new(big.Int).SetString(signSub[1], 16)
|
||||
return r, s
|
||||
}
|
||||
|
||||
func rSToSign(r *big.Int, s *big.Int) string {
|
||||
rStr := r.Text(16)
|
||||
sStr := s.Text(16)
|
||||
return fmt.Sprintf("%s#%s", rStr, sStr)
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package sm4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
SELF_PRI = "EA7CB6F907A96264D6763F8C46AB96B476538D2ABC880A459E10BE5A1C30013D"
|
||||
|
||||
SELF_PUB = "04363DF574D4FE34EE58FB8A3F7CB08E6CA5EBB3B7335CBAE10A2900551F6450AB3AD25DBC0A76EFA9E6D44D2C51E3027483F7BFD09996457888BAFD1AF673817F"
|
||||
|
||||
PARTY_PRI = "EEB0A34DE1F05154E4B96E50BFC1F8B9750EEAE799F5708C7AFBABB9AFCFA1BF"
|
||||
|
||||
PARTY_PUB = "0420425DF33945C9D5596A33ED60ABEEFD0165C27BA7D6C95D37344E9223149FEAF4C10CEACD7EC88E8DD1E0BDEA71FD09BE2077A1BDC61BC45587B7CC3613F85A"
|
||||
)
|
||||
|
||||
func TestGenerateKey(t *testing.T) {
|
||||
hexPri, publicKeyHex := GenerateKey()
|
||||
fmt.Println(hexPri, publicKeyHex)
|
||||
}
|
||||
|
||||
func TestSM4Encrypt(t *testing.T) {
|
||||
t.Log(encrypt())
|
||||
}
|
||||
|
||||
func TestSM4Decrypt(t *testing.T) {
|
||||
|
||||
uid, en := encrypt()
|
||||
//uid := "1729382256910270475"
|
||||
//en := "{\"accessToken\":\"77F59F157466F309E703F43CFDCFFECF\",\"encryptKey\":\"04237241E4A465C18645985B3C1DAE987B5DDF1C077AA27D677C843C52E833A24711C63F2512D1A4C37E85A5C9CEAC94156C97460CB5E8966CAD2A0C2596A64ED69CF3306D031C4AADAA73D165FB7EEC34E5AAF532A301169847560329F7F1E40E9FD09EB191976BB49ABFE611E05158EF\",\"request\":\"mkuquQ1RB2AtZYzBtWtLPJ3MMULWj7I5RmK3dKENYVW8OgB//I/+MAD/XnjxYYJlRWM8uL/rWL9o\\r\\n0L7W9fSBvOXWwz8reiwcAF/JZ5dnacZtVe0NPujDfeVIJp+9ua7hxQcegcEsIRS9CQqtF/rJN7M9\\r\\nxxCLSzEiJY8bIdRLBsfmB0uVIE2144s2tH7Q8R2fSOVbiSTH1PW3Ye0kkyCcBw==\",\"signature\":\"ed99a2ce827a4d443e2639ccfb78865e913854e2d61d1746dafb640e19cbb4f8#3793b1cac082d9e1cdfc2b7b8387a8c29e44b2f3fb35b352d02f1b2c9321e0a7\"}"
|
||||
decrypt, err := Sm4Decrypt(uid, SELF_PRI, PARTY_PUB, en, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.Log(decrypt)
|
||||
}
|
||||
|
||||
func encrypt() (string, string) {
|
||||
uid := strconv.FormatInt(int64(5476377146882523149), 10)
|
||||
data := "{\"pay_channel_id\":1729382256910270476,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523149,\"timestamp\":1723096731}"
|
||||
en, err := Sm4Encrypt(uid, PARTY_PRI, SELF_PUB, data, "", true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return uid, en
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package mq
|
||||
|
||||
import (
|
||||
common3 "PaymentCenter/app/constants/common"
|
||||
mq "PaymentCenter/app/utils/mq/mqs"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
@ -25,8 +23,8 @@ func (this *CMqManager) InitMq() {
|
|||
this.mqs = make(map[string]Imq)
|
||||
//this.mqs[common.MQ_RABBIT] = RabbitMq{}
|
||||
//this.mqs[common.MQ_NSQ] = NsqMq{}
|
||||
this.mqs[common3.MQ_NATS] = mq.NatsMq{}
|
||||
this.mqs[common3.MQ_KFK] = mq.KafkaMq{}
|
||||
//this.mqs[common3.MQ_NATS] = mq.NatsMq{}
|
||||
//this.mqs[common3.MQ_KFK] = mq.KafkaMq{}
|
||||
}
|
||||
func (this *CMqManager) GetMqByName(name string) Imq {
|
||||
once.Do(func() {
|
||||
|
|
|
@ -1,89 +1,89 @@
|
|||
package mq
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Shopify/sarama"
|
||||
"github.com/qit-team/snow-core/redis"
|
||||
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type KafkaMq struct {
|
||||
}
|
||||
|
||||
// 同步
|
||||
func (n KafkaMq) Produce(name string, log interface{}, delayTime int, args ...interface{}) error {
|
||||
kafConfig := sarama.NewConfig()
|
||||
kafConfig.Producer.RequiredAcks = sarama.WaitForAll // 发送完数据需要leader和follow都确认
|
||||
kafConfig.Producer.Partitioner = sarama.NewRandomPartitioner // 新选出一个partition
|
||||
kafConfig.Producer.Return.Successes = true // 成功交付的消息将在success channel返回
|
||||
|
||||
// 构造一个消息
|
||||
msg := &sarama.ProducerMessage{}
|
||||
msg.Topic = name
|
||||
var data, _ = json.Marshal(log)
|
||||
msg.Value = sarama.StringEncoder(string(data))
|
||||
// 连接kafka
|
||||
client, err := sarama.NewSyncProducer(config.GetConf().KafkaUrl, kafConfig)
|
||||
if err != nil {
|
||||
fmt.Println("producer closed, err:", err)
|
||||
return nil
|
||||
}
|
||||
defer client.Close()
|
||||
// 发送消息
|
||||
pid, offset, err := client.SendMessage(msg)
|
||||
if err != nil {
|
||||
utils.Log(nil, "send msg failed, err:", err, pid, offset)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n KafkaMq) Consume(name string, hand interface{}) {
|
||||
consumer, err := sarama.NewConsumer(config.GetConf().KafkaUrl, nil)
|
||||
if err != nil {
|
||||
utils.Log(nil, "kafka comsume", err.Error())
|
||||
return
|
||||
}
|
||||
partitionList, err := consumer.Partitions(name) // 根据topic取到所有的分区
|
||||
if err != nil {
|
||||
utils.Log(nil, "kafka comsume", err.Error())
|
||||
return
|
||||
}
|
||||
//utils.Log(nil,"kafka comsume",name,partitionList)
|
||||
for partition := range partitionList { // 遍历所有的分区
|
||||
// 针对每个分区创建一个对应的分区消费者
|
||||
var offsetReDis, _ = redis.GetRedis().Incr(context.Background(), "kafka_consume:"+strconv.Itoa(int(partition))).Result() //保证多消费者不重复消费
|
||||
var offset int64 = sarama.OffsetNewest
|
||||
if offsetReDis > 0 {
|
||||
//offset = int64(offsetReDis)
|
||||
}
|
||||
pc, err := consumer.ConsumePartition(name, int32(partition), offset)
|
||||
//utils.Log(nil,"partion",int32(partition))
|
||||
if err != nil {
|
||||
fmt.Printf("failed to start consumer for partition %d,err:%v\n", partition, err)
|
||||
return
|
||||
}
|
||||
defer pc.AsyncClose()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
// 异步从每个分区消费信息
|
||||
go func(sarama.PartitionConsumer) {
|
||||
for msg := range pc.Messages() {
|
||||
defer wg.Done()
|
||||
var handler = hand.(func(tag uint64, ch interface{}, msg []byte))
|
||||
handler(0, nil, msg.Value)
|
||||
//utils.Log(nil,"hand msg",string(msg.Value),msg.Offset)
|
||||
}
|
||||
}(pc)
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
func (n KafkaMq) DelyConsume(name string, hand interface{}) {
|
||||
|
||||
}
|
||||
//
|
||||
//import (
|
||||
// "PaymentCenter/app/utils"
|
||||
// "PaymentCenter/config"
|
||||
// "context"
|
||||
// "fmt"
|
||||
// "github.com/Shopify/sarama"
|
||||
// "github.com/qit-team/snow-core/redis"
|
||||
//
|
||||
// "strconv"
|
||||
// "sync"
|
||||
//)
|
||||
//
|
||||
//type KafkaMq struct {
|
||||
//}
|
||||
//
|
||||
//// 同步
|
||||
//func (n KafkaMq) Produce(name string, log interface{}, delayTime int, args ...interface{}) error {
|
||||
// //kafConfig := sarama.NewConfig()
|
||||
// //kafConfig.Producer.RequiredAcks = sarama.WaitForAll // 发送完数据需要leader和follow都确认
|
||||
// //kafConfig.Producer.Partitioner = sarama.NewRandomPartitioner // 新选出一个partition
|
||||
// //kafConfig.Producer.Return.Successes = true // 成功交付的消息将在success channel返回
|
||||
// //
|
||||
// //// 构造一个消息
|
||||
// //msg := &sarama.ProducerMessage{}
|
||||
// //msg.Topic = name
|
||||
// //var data, _ = json.Marshal(log)
|
||||
// //msg.Value = sarama.StringEncoder(string(data))
|
||||
// //// 连接kafka
|
||||
// //client, err := sarama.NewSyncProducer(config.GetConf().KafkaUrl, kafConfig)
|
||||
// //if err != nil {
|
||||
// // fmt.Println("producer closed, err:", err)
|
||||
// // return nil
|
||||
// //}
|
||||
// //defer client.Close()
|
||||
// //// 发送消息
|
||||
// //pid, offset, err := client.SendMessage(msg)
|
||||
// //if err != nil {
|
||||
// // utils.Log(nil, "send msg failed, err:", err, pid, offset)
|
||||
// // return nil
|
||||
// //}
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//func (n KafkaMq) Consume(name string, hand interface{}) {
|
||||
// consumer, err := sarama.NewConsumer(config.GetConf().KafkaUrl, nil)
|
||||
// if err != nil {
|
||||
// utils.Log(nil, "kafka comsume", err.Error())
|
||||
// return
|
||||
// }
|
||||
// partitionList, err := consumer.Partitions(name) // 根据topic取到所有的分区
|
||||
// if err != nil {
|
||||
// utils.Log(nil, "kafka comsume", err.Error())
|
||||
// return
|
||||
// }
|
||||
// //utils.Log(nil,"kafka comsume",name,partitionList)
|
||||
// for partition := range partitionList { // 遍历所有的分区
|
||||
// // 针对每个分区创建一个对应的分区消费者
|
||||
// var offsetReDis, _ = redis.GetRedis().Incr(context.Background(), "kafka_consume:"+strconv.Itoa(int(partition))).Result() //保证多消费者不重复消费
|
||||
// var offset int64 = sarama.OffsetNewest
|
||||
// if offsetReDis > 0 {
|
||||
// //offset = int64(offsetReDis)
|
||||
// }
|
||||
// pc, err := consumer.ConsumePartition(name, int32(partition), offset)
|
||||
// //utils.Log(nil,"partion",int32(partition))
|
||||
// if err != nil {
|
||||
// fmt.Printf("failed to start consumer for partition %d,err:%v\n", partition, err)
|
||||
// return
|
||||
// }
|
||||
// defer pc.AsyncClose()
|
||||
// var wg sync.WaitGroup
|
||||
// wg.Add(1)
|
||||
// // 异步从每个分区消费信息
|
||||
// go func(sarama.PartitionConsumer) {
|
||||
// for msg := range pc.Messages() {
|
||||
// defer wg.Done()
|
||||
// var handler = hand.(func(tag uint64, ch interface{}, msg []byte))
|
||||
// handler(0, nil, msg.Value)
|
||||
// //utils.Log(nil,"hand msg",string(msg.Value),msg.Offset)
|
||||
// }
|
||||
// }(pc)
|
||||
// wg.Wait()
|
||||
// }
|
||||
//}
|
||||
//func (n KafkaMq) DelyConsume(name string, hand interface{}) {
|
||||
//
|
||||
//}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -410,3 +411,54 @@ func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
|
|||
})
|
||||
return token, Claims, err
|
||||
}
|
||||
|
||||
func PopLast[T any](slice *[]T) (T, bool) {
|
||||
if len(*slice) == 0 {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
index := len(*slice) - 1
|
||||
lastElement := (*slice)[index]
|
||||
*slice = (*slice)[:index] // 移除最后一个元素
|
||||
return lastElement, true
|
||||
}
|
||||
|
||||
func SonicApiDataToStruct(data interface{}, structInterFace interface{}) (dataStruct interface{}, err error) {
|
||||
bytes, err := sonic.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = sonic.Unmarshal(bytes, &structInterFace)
|
||||
return structInterFace, err
|
||||
}
|
||||
|
||||
func ContainsString(slice []string, s string) bool {
|
||||
for _, item := range slice {
|
||||
if item == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断切片是否包含指定字符串
|
||||
func SliceInStr(s string, slice []string) bool {
|
||||
for _, v := range slice {
|
||||
if s == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 判断支付方式支付宝或者微信
|
||||
func PayType(payChannel int) int {
|
||||
switch payChannel {
|
||||
case common.PAY_CHANNEL_WECHAT_H5, common.PAY_CHANNEL_WECHAT_JSAPI, common.PAY_CHANNEL_WECHAT_NATIVE, common.PAY_CHANNEL_WECHAT_APP, common.PAY_CHANNEL_WECHAT_MINI:
|
||||
return common.PAY_CHANNLE_TYPE_WECHAT
|
||||
case common.PAY_CHANNEL_ALIPAY_JSAPI, common.PAY_CHANNEL_ALIPAY_WEB, common.PAY_CHANNEL_ALIPAY_MINI:
|
||||
return common.PAY_CHANNLE_TYPE_ZFB
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,10 @@ import (
|
|||
"PaymentCenter/app/jobs"
|
||||
"PaymentCenter/app/jobs/basejob"
|
||||
"PaymentCenter/config"
|
||||
"github.com/qit-team/snow-core/log/accesslogger"
|
||||
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"github.com/qit-team/snow-core/kernel/close"
|
||||
"github.com/qit-team/snow-core/kernel/container"
|
||||
"github.com/qit-team/snow-core/log/accesslogger"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"github.com/qit-team/snow-core/redis"
|
||||
)
|
||||
|
@ -26,6 +25,8 @@ func Bootstrap(conf *config.Config) (err error) {
|
|||
//注册db服务
|
||||
//第一个参数为注入别名,第二个参数为配置,第三个参数可选为是否懒加载
|
||||
err = db.Pr.Register(db.SingletonMain, conf.Db)
|
||||
//cacher := caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 1000)
|
||||
//db.GetDb().SetDefaultCacher(cacher)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
@ -6,4 +6,4 @@ arch=$2 #架构amd64
|
|||
rootPath=$(cd `dirname $0`/../../; pwd)
|
||||
|
||||
#编译
|
||||
GOOS=$os GOARCH=$arch go build -o build/bin/snow main.go
|
||||
GOOS=$os GOARCH=$arch go build -o build/bin/snow main.go
|
|
@ -22,6 +22,7 @@ type Config struct {
|
|||
Debug bool `toml:"Debug"`
|
||||
PrometheusCollectEnable bool `toml:"PrometheusCollectEnable"`
|
||||
SkyWalkingOapServer string `toml:"SkyWalkingOapServer"`
|
||||
TimeOut int64 `toml:"TimeOut"`
|
||||
Log config.LogConfig `toml:"Log"`
|
||||
Redis config.RedisConfig `toml:"Redis"`
|
||||
Mns config.MnsConfig `toml:"AliMns"`
|
||||
|
@ -36,6 +37,9 @@ type Config struct {
|
|||
OpenApi OpenApi `toml:"OpenApi"`
|
||||
Jwt Jwt `toml:"Jwt"`
|
||||
AliOss AliOss `toml:"AliOss"`
|
||||
AdminGate []string `toml:"AdminGate"`
|
||||
CronConfig CronConfig `toml:"CronConfig"`
|
||||
PayService PayService `toml:"PayService"`
|
||||
}
|
||||
|
||||
type AliOss struct {
|
||||
|
@ -82,6 +86,17 @@ type Nacos struct {
|
|||
Port int64
|
||||
}
|
||||
|
||||
type CronConfig struct {
|
||||
CloseOrderTime int `toml:"CloseOrderTime"`
|
||||
QueryOrderTime int `toml:"QueryOrderTime"`
|
||||
ConcurrentNumber int `toml:"ConcurrentNumber"`
|
||||
}
|
||||
|
||||
type PayService struct {
|
||||
Host string `toml:"Host"`
|
||||
IsProd bool `toml:"IsProd"`
|
||||
}
|
||||
|
||||
func newConfig() *Config {
|
||||
return new(Config)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
/**
|
||||
*事件触发
|
||||
event.EventManger.TrigerEvent(common.Event_USER_LOG_IN, param)
|
||||
event.EventManger.TrigerEvent(payCommon.Event_USER_LOG_IN, param)
|
||||
*/
|
||||
|
||||
var EventManger *EventManagerFactory
|
||||
|
|
35
go.mod
35
go.mod
|
@ -6,9 +6,13 @@ require (
|
|||
gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2
|
||||
github.com/BurntSushi/toml v0.4.1
|
||||
github.com/Shopify/sarama v1.19.0
|
||||
github.com/ZZMarquis/gm v1.3.2
|
||||
github.com/ahmetb/go-linq/v3 v3.2.0
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
github.com/bytedance/sonic v1.10.2
|
||||
github.com/forgoer/openssl v1.6.0
|
||||
github.com/gin-gonic/gin v1.7.7
|
||||
github.com/go-pay/gopay v1.5.103
|
||||
github.com/go-playground/locales v0.14.0
|
||||
github.com/go-playground/universal-translator v0.18.0
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
|
@ -21,6 +25,7 @@ require (
|
|||
github.com/qit-team/snow-core v0.1.28
|
||||
github.com/qit-team/work v0.3.11
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
|
||||
github.com/swaggo/gin-swagger v1.3.3
|
||||
github.com/swaggo/swag v1.7.9
|
||||
|
@ -29,6 +34,8 @@ require (
|
|||
google.golang.org/grpc v1.56.3
|
||||
google.golang.org/protobuf v1.30.0
|
||||
gopkg.in/go-playground/validator.v9 v9.31.0
|
||||
xorm.io/builder v0.3.9
|
||||
xorm.io/xorm v1.2.5
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -46,17 +53,25 @@ require (
|
|||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/eapache/go-resiliency v1.1.0 // indirect
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
|
||||
github.com/eapache/queue v1.1.0 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-pay/crypto v0.0.1 // indirect
|
||||
github.com/go-pay/errgroup v0.0.2 // indirect
|
||||
github.com/go-pay/util v0.0.2 // indirect
|
||||
github.com/go-pay/xlog v0.0.3 // indirect
|
||||
github.com/go-pay/xtime v0.0.2 // indirect
|
||||
github.com/go-playground/validator/v10 v10.9.0 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.4 // indirect
|
||||
github.com/goccy/go-json v0.8.1 // indirect
|
||||
|
@ -66,10 +81,13 @@ require (
|
|||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/hetiansu5/accesslog v1.0.0 // indirect
|
||||
github.com/hetiansu5/cores v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
|
||||
github.com/lestrrat-go/strftime v1.0.5 // indirect
|
||||
|
@ -88,29 +106,30 @@ require (
|
|||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||
github.com/tidwall/gjson v1.12.1 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/arch v0.6.0 // indirect
|
||||
golang.org/x/crypto v0.25.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.1.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
stathat.com/c/consistent v1.0.0 // indirect
|
||||
xorm.io/builder v0.3.9 // indirect
|
||||
xorm.io/core v0.7.3 // indirect
|
||||
xorm.io/xorm v1.2.5 // indirect
|
||||
)
|
||||
|
|
80
go.sum
80
go.sum
|
@ -58,9 +58,13 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
|
|||
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/ZZMarquis/gm v1.3.2 h1:lFtpzg5zeeVMZ/gKi0gtYcKLBEo9XTqsZDHDz6s3Gow=
|
||||
github.com/ZZMarquis/gm v1.3.2/go.mod h1:wWbjZYgruQVd7Bb8UkSN8ujU931kx2XUW6nZLCiDE0Q=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
|
||||
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
||||
github.com/ahmetb/go-linq/v3 v3.2.0 h1:BEuMfp+b59io8g5wYzNoFe9pWPalRklhlhbiU3hYZDE=
|
||||
github.com/ahmetb/go-linq/v3 v3.2.0/go.mod h1:haQ3JfOeWK8HpVxMtHHEMPVgBKiYyQ+f1/kLZh/cj9U=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
|
@ -108,6 +112,10 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
|||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
|
@ -115,6 +123,13 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
|||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
||||
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
|
@ -173,6 +188,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k=
|
||||
|
@ -208,6 +224,18 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
|
|||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-pay/crypto v0.0.1 h1:B6InT8CLfSLc6nGRVx9VMJRBBazFMjr293+jl0lLXUY=
|
||||
github.com/go-pay/crypto v0.0.1/go.mod h1:41oEIvHMKbNcYlWUlRWtsnC6+ASgh7u29z0gJXe5bes=
|
||||
github.com/go-pay/errgroup v0.0.2 h1:5mZMdm0TDClDm2S3G0/sm0f8AuQRtz0dOrTHDR9R8Cc=
|
||||
github.com/go-pay/errgroup v0.0.2/go.mod h1:0+4b8mvFMS71MIzsaC+gVvB4x37I93lRb2dqrwuU8x8=
|
||||
github.com/go-pay/gopay v1.5.103 h1:tjteCpcApf0CpiwKywMl6UnbLkMeYLJVEuVBtsQbyb8=
|
||||
github.com/go-pay/gopay v1.5.103/go.mod h1:4+jKRvgmB8clKN1/E9M60miXKbnZ8wWGcg/Hsxn7k44=
|
||||
github.com/go-pay/util v0.0.2 h1:goJ4f6kNY5zzdtg1Cj8oWC+Cw7bfg/qq2rJangMAb9U=
|
||||
github.com/go-pay/util v0.0.2/go.mod h1:qM8VbyF1n7YAPZBSJONSPMPsPedhUTktewUAdf1AjPg=
|
||||
github.com/go-pay/xlog v0.0.3 h1:avyMhCL/JgBHreoGx/am/kHxfs1udDOAeVqbmzP/Yes=
|
||||
github.com/go-pay/xlog v0.0.3/go.mod h1:mH47xbobrdsSHWsmFtSF5agWbMHFP+tK0ZbVCk5OAEw=
|
||||
github.com/go-pay/xtime v0.0.2 h1:7YR4/iuELsEHpJ6LUO0SVK80hQxDO9MLCfuVYIiTCRM=
|
||||
github.com/go-pay/xtime v0.0.2/go.mod h1:W1yRbJaSt4CSBcdAtLBQ8xajiN/Pl5hquGczUcUE9xE=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
|
@ -297,8 +325,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
|
@ -365,6 +393,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
|||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
|
@ -414,6 +443,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
|
|||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
|
@ -445,6 +476,10 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
@ -668,9 +703,11 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ
|
|||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
|
@ -680,6 +717,8 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
|
@ -687,6 +726,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
|
@ -710,6 +750,8 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
|
|||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
|
@ -772,6 +814,9 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
|||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
|
||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
|
||||
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
@ -793,8 +838,8 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5
|
|||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -831,8 +876,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -885,8 +930,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -911,8 +956,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -987,8 +1032,9 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -1000,8 +1046,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -1071,8 +1117,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -1373,7 +1419,9 @@ modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
|||
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
|
||||
modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
|
||||
modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
|
|
Loading…
Reference in New Issue