Compare commits

...

22 Commits

Author SHA1 Message Date
Rzy ee912a204d <feat>退款 2024-08-08 14:52:30 +08:00
Rzy aa43040aa2 <feat>调整代码结构 2024-08-08 11:15:50 +08:00
Rzy cb14c35aa9 <feat>调整代码结构 2024-08-08 10:48:25 +08:00
Rzy ebea5c52e0 <fix>处理bug 2024-08-08 09:52:05 +08:00
Rzy 40dfffe31a <fix>bug修改 2024-08-08 09:49:27 +08:00
陈俊宏 58f8cedb85 Merge branch 'dev/dev1.0' into feature_413_cjh 2024-08-08 09:43:02 +08:00
陈俊宏 d6bf4dd952 回调log记录 2024-08-08 09:42:46 +08:00
Rzy 7ed1ca131b Merge branch 'feature/rzy/api_1.0' into dev/dev1.0 2024-08-08 09:30:39 +08:00
陈俊宏 30b83b3645 Merge branch 'feature_413_cjh' into dev/dev1.0 2024-08-08 09:20:49 +08:00
陈俊宏 62d050c02f 回调log 2024-08-08 09:20:25 +08:00
wolter 3061987dae Merge branch 'refs/heads/feature/zxp' into dev/dev1.0 2024-08-08 09:18:49 +08:00
wolter 3d5e33fed0 Merge remote-tracking branch 'refs/remotes/origin/feature/rzy/api_1.0' into dev/dev1.0
# Conflicts:
#	app/constants/errorcode/error_code.go
#	app/services/thirdpay/notify/notify.go
2024-08-08 09:14:08 +08:00
wolter bf1bc4b1a2 后台,密钥对生成 2024-08-07 17:14:03 +08:00
wolter 514104a391 定时查询退款单 2024-08-07 10:49:06 +08:00
陈俊宏 ad56b5f0e5 Merge branch 'dev/dev1.0' into feature_413_cjh 2024-08-07 10:32:37 +08:00
陈俊宏 82ef285e7d 订单查询 2024-08-07 10:32:15 +08:00
陈俊宏 ca42c43bd2 回调 触发下游回调 2024-08-07 10:22:40 +08:00
陈俊宏 6ab982e874 Merge remote-tracking branch 'origin/feature/rzy/api_1.0' into feature_413_cjh 2024-08-07 10:16:13 +08:00
wolter c79e316233 Merge remote-tracking branch 'refs/remotes/origin/feature/rzy/api_1.0' into feature/zxp 2024-08-07 10:03:42 +08:00
陈俊宏 75d68a3032 Merge remote-tracking branch 'origin/feature/rzy/api_1.0' into feature_413_cjh 2024-08-07 09:00:49 +08:00
wolter e261a39cf5 Merge remote-tracking branch 'refs/remotes/origin/feature/rzy/api_1.0' into feature/zxp 2024-08-07 08:48:28 +08:00
陈俊宏 68b9e16864 支付回调处理 2024-08-06 18:00:49 +08:00
34 changed files with 578 additions and 416 deletions

View File

@ -6,14 +6,13 @@ import (
"PaymentCenter/app/http/entities"
"PaymentCenter/app/http/entities/backend"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/models/orderthirdpaylogmodel"
"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"
@ -83,7 +82,7 @@ func closeOrder() {
if response.Code == payCommon.PAY_SUCCESS_CODE {
orderIds = append(orderIds, orderInfo.Id)
} else {
utils.Log(nil, "关闭订单,上游支付失败", response)
utils.Log(nil, "关闭订单,上游失败", response)
}
}
// 修改订单状态为关闭
@ -172,64 +171,115 @@ func queryOrder() {
// 成功
status = common.ORDER_STATUS_PAYED
case "REFUND":
// 退款
status = common.ORDER_STATUS_REFUND
// 退款 订单支付完成才能退款,所以支付单的状态是支付完成
status = common.ORDER_STATUS_PAYED
case "NOTPAY":
// 未支付
return
case "CLOSED":
// 关闭
status = common.ORDER_STATUS_CLOSE
}
// 回调通知下游 todo
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, status, int(result.Result.PayerTotal), "")
utils.Log(nil, "主动查询订单支付状态,回调下游", notifyResult)
}
}(orderInfo)
}
wg.Wait()
}
}
// 更新订单状态 todo
orderUpdate := ordersmodel.Orders{
Id: orderInfo.Id,
Status: status,
PayerTotal: int(result.Result.PayerTotal),
// 主动查询退款订单状态
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
}
session := ordersmodel.GetInstance().GetDb().NewSession()
if err = session.Begin(); err != nil {
utils.Log(nil, "主动查询订单支付状态,更新订单状态失败", err)
// 发起查询
result := paymentService.OrderRefundQuery(ctx, query)
utils.Log(nil, "主动查询退款订单状态,上游返回数据", result)
// 查询成功,校验状态
var status int
if result.Code == payCommon.PAY_SUCCESS_CODE {
// 退款状态 0未申请1退款中2退款成功3退款失败
switch result.Result.RefundStatus {
case 0:
// 未申请
utils.Log(nil, "主动查询退款订单状态,未申请", status)
return
}
defer func() {
if err != nil {
session.Rollback()
} else {
err = session.Commit()
}
}()
orderLogRepo := data.NewOrderThirdPayLogRepo(session)
orderRepo := data.NewOrderRepo(session)
conn := builder.NewCond()
conn = conn.And(builder.Eq{"id": orderInfo.Id})
_, err = orderRepo.OrderUpdate(&orderUpdate, conn)
if err != nil {
utils.Log(nil, "主动查询订单支付状态,更新订单状态失败", err)
case 1:
// 退款中
status = common.ORDER_STATUS_PAYING
return
case 2:
// 退款成功
status = common.ORDER_STATUS_PAYED
case 3:
// 退款失败
status = common.ORDER_STATUS_FAILED
}
// 写入日志
body, _ := json.Marshal(result)
log := orderthirdpaylogmodel.OrderThirdPayLog{
OrderId: orderInfo.Id,
PayCallback: string(body),
Status: 0,
PayParam: fmt.Sprintf(`{"pay_channel_id":%d}`, orderInfo.PayChannelId),
Type: common.THIRD_ORDER_TYPE_ORDER_QUERY,
MerchantCallback: "{}",
}
_, err = orderLogRepo.OrderThirdPayLogInsertOne(&log)
if err != nil {
utils.Log(nil, "主动查询订单支付状态,写入支付日志失败", err)
}
// 回调通知下游 todo
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, status, int(result.Result.RefundFee), "")
utils.Log(nil, "主动查询退款订单状态,回调下游", notifyResult)
}
}(orderInfo)
}

View File

@ -17,4 +17,5 @@ func RegisterSchedule(c *cron.Cron) {
//c.AddFunc("@every 10s", test)
c.AddFunc("@every 60s", closeOrder)
c.AddFunc("@every 10s", queryOrder)
c.AddFunc("@every 60s", queryRefundOrder)
}

View File

@ -22,13 +22,12 @@ const (
ADMIN_USER_NAME = "User-Name"
ADMIN_USER_INCLUDEUSERS = "Include-Users"
// '订单状态: 1待支付、2支付中、3支付成功、4支付失败、5订单关闭 6支付完成后退款,
// '订单状态: 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
ORDER_STATUS_REFUND = 6
// 订单类型1支付2退款
ORDER_TYPE_PAY = 1

View File

@ -47,7 +47,9 @@ const (
AppSM4DecryptFail = 1231
AppSM4EncryptKeyNotFound = 1232
AppSM4EncryptFail = 1233
AppAesEncryptFail = 1240
AppAesEncryptFail = 1234
// 加密方式不存在
EncryptTypeNotFound = 1241
//渠道
PayChannelNotFound = 1300
@ -71,8 +73,9 @@ const (
//回调
NotifySendFail = 1600
//预支付
PrePayFail = 1701
//订单结果
PrePayFail = 1701
PreRefundFail = 1702
)
var MsgEN = map[int]string{
@ -116,6 +119,8 @@ var MsgZH = map[int]string{
AppAesEncryptFail: "aes 加密失败",
EncryptTypeNotFound: "加密方式不存在",
PayChannelNotFound: "支付方式不存在",
PayChannelNotBuild: "支付方式尚未开通",
PayChannelExtJsonError: "支付方式扩展参数错误",

View File

@ -7,7 +7,9 @@ import (
"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"
)
@ -60,12 +62,19 @@ func GenerateDecrypt(c *gin.Context) {
var publicKey, privateKey string
var err error
switch req.KeyType {
default:
case "sm2":
publicKey, privateKey, err = sm2.GenerateSM2Key()
if err != nil {
controllers.Error(c, errorcode.SystemError, err.Error())
return
}
case "rsa":
publicKey, privateKey, err = rsa.GenerateKey()
case "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{

View File

@ -21,17 +21,17 @@ func PayUrl(c *gin.Context) {
controllers.ApiRes(c, nil, check.CheckCode)
return
}
check.CheckOrder()
check.CheckOrderPay()
if check.CheckCode != errorcode.Success {
controllers.ApiRes(c, nil, check.CheckCode)
return
}
pay := thirdpay.ThirdPayWeb(check)
pay := thirdpay.ThirdPayUrl(check)
if pay.PayCode != errorcode.Success {
controllers.ApiRes(c, nil, pay.PayCode)
return
}
data := api.NewOrdersResp(pay.Order)
data := thirdpay.NewOrdersResp(pay.Order)
encryptData, errCode := api.EnCrypt(appCheckInfo.App, data)
if errCode != errorcode.Success {
@ -44,6 +44,24 @@ func PayUrl(c *gin.Context) {
return
}
func Refund(c *gin.Context) {
req := controllers.GetRequest(c).(*front.RefundReqs)
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)
encryptData, errCode := api.EnCrypt(appCheckInfo.App, data)
if errCode != errorcode.Success {
controllers.ApiRes(c, nil, refund.PayCode)
return
}
controllers.ApiRes(c, encryptData, refund.PayCode)
return
}
// 查询订单
func QueryOrder(c *gin.Context) {
req := controllers.GetRequest(c).(*front.QueryReqs)
@ -62,7 +80,7 @@ func QueryOrder(c *gin.Context) {
controllers.ApiRes(c, nil, code)
return
}
data := api.NewOrdersResp(&order)
data := thirdpay.NewOrdersResp(&order)
encryptData, errCode := api.EnCrypt(appCheckInfo.App, data)
if errCode != errorcode.Success {
controllers.ApiRes(c, nil, errCode)

View File

@ -65,6 +65,8 @@ func WxCallback(c *gin.Context) {
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())
@ -72,9 +74,6 @@ func WxCallback(c *gin.Context) {
return
}
// ====↓↓↓====异步通知应答====↓↓↓====
// 退款通知http应答码为200且返回状态码为SUCCESS才会当做商户接收成功否则会重试。
// 注意:重试过多会导致微信支付端积压过多通知而堵塞,影响其他正常通知。
c.JSON(http.StatusOK, &wechat.V3NotifyRsp{Code: gopay.SUCCESS, Message: "成功"})
return
}
@ -105,34 +104,27 @@ func AliCallback(c *gin.Context) {
}
var aliConfig paymentService.AliPay
var aliConfigModel struct {
PrivateKey string `json:"private_key"` // 应用私钥
AppPublicCert string `json:"app_public_cert"` // 应用公钥
AlipayRootCert string `json:"alipay_root_cert"` // 支付宝根证书
AlipayPublicCert string `json:"alipay_public_cert"` // 支付宝公钥
}
err := json.Unmarshal([]byte(payChannelModel.ExtJson), &aliConfigModel)
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 aliConfigModel.AlipayPublicCert == "" || aliConfigModel.PrivateKey == "" || aliConfigModel.AppPublicCert == "" || aliConfigModel.AlipayRootCert == "" {
if aliConfig.AlipayPublicCert == "" || aliConfig.PrivateKey == "" || aliConfig.AppPublicCert == "" || aliConfig.AlipayRootCert == "" {
logger.Error(c, "AliCallback-回调数据解析支付配置错误,解析出来的信息为空")
c.String(http.StatusBadRequest, "%s", "fail")
return
}
aliConfig.AppId = payChannelModel.AppId
aliConfig.PrivateKey = aliConfigModel.PrivateKey
aliConfig.AppPublicCert = aliConfigModel.AppPublicCert
aliConfig.AlipayRootCert = aliConfigModel.AlipayRootCert
aliConfig.AlipayPublicCert = aliConfigModel.AlipayPublicCert
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())

View File

@ -96,5 +96,5 @@ func (a *AppUpdateRequest) RequestToDb() (db appmodel.App) {
}
type GenerateDecryptKeyRequest struct {
KeyType int `json:"key_type" label:"密钥类型"`
KeyType string `json:"key_type" form:"key_type" label:"密钥类型"`
}

View File

@ -12,16 +12,25 @@ type RequestBody struct {
Key string `json:"key" validate:"max=32"`
}
type PayReqs struct {
type PayCommonReqBody struct {
ApiCommonBody
PayChannelId int64 `json:"pay_channel_id" validate:"required" label:"支付渠道"`
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
OrderType int `json:"order_type" 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
OutTradeNo string `json:"out_trade_no" label:"外侧商户订单号"`
OrderId string `json:"order_id" label:"平台订单号"`
}
type PayUrlResp struct {
Order string `json:"order"`
Url string `json:"url"`

View File

@ -149,7 +149,6 @@ func ValidatePayRequest() gin.HandlerFunc {
//获取app信息
appCheck := services.GetAppCheck(requestDataStruct.AppId, c.ClientIP())
//存入请求记录
if appCheck.Code != errorcode.Success {
controllers.ApiRes(c, nil, appCheck.Code)
return

View File

@ -6,7 +6,8 @@ import (
)
var FrontRequestMap = map[string]func() interface{}{
common.FRONT_V1 + "/pay/url": func() interface{} { return new(front.PayReqs) },
common.FRONT_V1 + "/pay/url": func() interface{} { return new(front.PayReqs) },
common.FRONT_V1 + "/pay/refund": func() interface{} { return new(front.RefundReqs) },
}
var FrontRequestMapBeforeDecrypt = map[string]func() interface{}{

View File

@ -60,6 +60,7 @@ func RegisterRoute(router *gin.Engine) {
{
pay.POST("/url", front.PayUrl)
pay.POST("/query", front.QueryOrder) //查询订单
pay.POST("/refund", front.Refund)
}
}

View File

@ -13,20 +13,21 @@ var (
// 实体
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)"`
OutTreadNo string `xorm:"'out_tread_no' varchar(50)"`
OrderType int `xorm:"'order_type' TINYINT"`
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"`
Id int64
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
PayChannelId int64 `xorm:"'pay_channel_id' bigint(20)"`
AppId int64 `xorm:"'app_id' bigint(20)"`
OutTreadNo string `xorm:"'out_tread_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 {

View File

@ -18,7 +18,7 @@ func (r *SM2) Encrypt(data []byte) (encryptData []byte, errCode int) {
return nil, errorcode.AppSM2EncryptKeyNotFound
}
encryptDataString, err := sm2.SM2Encrypt(string(data), r.App.PrivateKey)
encryptDataString, err := sm2.SM2Encrypt(string(data), r.App.MerchantPublicKey)
if err != nil {
return nil, errorcode.AppSM2EncryptFail
}

View File

@ -105,6 +105,7 @@ func CheckApp(appCheckIn *AppCheck) {
appCheckIn.App, errCode = AppFindOne(entities.IdRequest{Id: appCheckIn.AppId})
if errCode != errorcode.Success {
appCheckIn.Code = errCode
return
}
//检查app可用性
appCheckIn.Check()

View File

@ -100,7 +100,7 @@ func PayChannelFindOne(channel *paychannelmodel.PayChannel, conn builder.Cond, c
channelInfo, err := repo.PayChannelFindOne(channel, conn, col...)
if err != nil {
if err == sql.ErrNoRows {
return nil, errorcode.MerchantNotFound
return nil, errorcode.PayChannelNotFound
}
return nil, errorcode.SystemError
}

View File

@ -1,9 +1,5 @@
package api
import (
"PaymentCenter/app/models/ordersmodel"
)
type OrdersResp struct {
OrderNo int64 `json:"order_no"`
OrderType int `json:"order_type"`
@ -20,18 +16,6 @@ type OrdersWithUrl struct {
Url string
}
func NewOrdersResp(db *ordersmodel.Orders) *OrdersResp {
return &OrdersResp{
OrderNo: db.Id,
OutTreadNo: db.OutTreadNo,
Status: db.Status,
OrderType: db.OrderType,
Amount: db.Amount,
Desc: db.Desc,
CreateTime: db.CreateTime.Format("2006-01-02 15:04:05"),
}
}
func (o *OrdersResp) WithUrl(url string) *OrdersWithUrl {
return &OrdersWithUrl{
Order: o,

View File

@ -3,6 +3,7 @@ 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"
@ -12,6 +13,9 @@ import (
)
type Pay struct {
Merchant *merchantmodel.Merchant
Channel *paychannelmodel.PayChannel
paycheck *PayCheck
Order *ordersmodel.Orders
PayCode int
@ -25,16 +29,20 @@ func NewPay(paycheck *PayCheck) *Pay {
}
}
func (w *Pay) CreateOrder() {
func (w *Pay) CreateOrder(order_type int) {
if _, ok := common.OrderTypeList[order_type]; !ok { //判断是否是支持的支付渠道
w.PayCode = errorcode.PayChannelNotFound
return
}
w.Order, w.PayCode = services.OrderCreate(&ordersmodel.Orders{
MerchantId: w.paycheck.Merchant.Id,
PayChannelId: w.paycheck.Channel.Id,
AppId: w.paycheck.Channel.Id,
OutTreadNo: w.paycheck.WebPayReqs.OutTradeNo,
OrderType: w.paycheck.WebPayReqs.OrderType,
Amount: w.paycheck.WebPayReqs.Amount,
ExtJson: w.paycheck.WebPayReqs.ExtJson,
Desc: w.paycheck.WebPayReqs.Desc,
OutTreadNo: w.paycheck.Reqs.OutTradeNo,
OrderType: order_type,
Amount: w.paycheck.Reqs.Amount,
ExtJson: w.paycheck.Reqs.ExtJson,
Desc: w.paycheck.Reqs.Desc,
Status: common.ORDER_STATUS_WAITPAY,
},
)
@ -46,7 +54,7 @@ func (w *Pay) PayUrl() (url string) {
ok bool
)
thirdPay := &paymentService.PayOrderRequest{
PayChannelId: w.paycheck.WebPayReqs.PayChannelId,
PayChannelId: w.paycheck.Reqs.PayChannelId,
OrderId: w.Order.Id,
ChannelType: w.paycheck.Channel.ChannelType,
Description: w.Order.Desc,
@ -77,3 +85,37 @@ func (w *Pay) PayUrl() (url string) {
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.paycheck.OldOrder.Id,
RefundReason: w.paycheck.Reqs.Desc,
RefundAmount: int64(w.paycheck.Reqs.Amount),
PayChannel: w.paycheck.Channel.ChannelType,
}
if refundFunc, ok = RefundWayList[w.paycheck.Channel.ChannelType]; !ok {
w.PayCode = errorcode.PayChannelNotBuild
return
}
err := refundFunc(thirdPayRefund, w.paycheck.Channel)
if err != nil {
w.PayCode = errorcode.PayChannelExtJsonError
return
}
res := paymentService.OrderRefund(*w.paycheck.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
}
} else {
w.PayCode = errorcode.PreRefundFail
}
return
}

View File

@ -4,9 +4,9 @@ import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/services"
"PaymentCenter/app/services/thirdpay/types"
"xorm.io/builder"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/models/merchantmodel"
"PaymentCenter/app/models/orderrequestlogmodel"
"PaymentCenter/app/models/ordersmodel"
@ -16,7 +16,7 @@ import (
type PayCheck struct {
ctx *context.Context
WebPayReqs *front.PayReqs
Reqs *types.Reqs
AppCheck *services.AppCheck
RequestLog *orderrequestlogmodel.OrderRequestLog
Channel *paychannelmodel.PayChannel
@ -25,29 +25,32 @@ type PayCheck struct {
CheckCode int
}
func NewPayCheck(ctx *context.Context, reqs *front.PayReqs, appCheck *services.AppCheck, ip string) *PayCheck {
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,
WebPayReqs: reqs,
AppCheck: appCheck,
CheckCode: appCheck.Code,
ctx: ctx,
Reqs: reqs,
AppCheck: appCheck,
CheckCode: appCheck.Code,
}
}
func (w *PayCheck) CheckForm() {
if _, ok := common.OrderTypeList[w.WebPayReqs.OrderType]; !ok { //判断是否是支持的支付渠道
w.CheckCode = errorcode.PayChannelNotFound
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.WebPayReqs.PayChannelId})
conn = conn.And(builder.Eq{"id": w.Reqs.PayChannelId})
w.Channel, w.CheckCode = services.GetAndCheckPayChannel(&paychannelmodel.PayChannel{}, conn)
}
@ -57,9 +60,45 @@ func (w *PayCheck) CheckMerchant() {
w.Merchant, w.CheckCode = services.GetAndCheckMerchant(&merchantmodel.Merchant{}, conn)
}
func (w *PayCheck) CheckOrder() {
func (w *PayCheck) CheckOrderPay() {
w.GetOrder()
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()
if w.OldOrder == nil {
w.CheckCode = errorcode.OrdersNotFound
}
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_WAITPAY:
w.CheckCode = errorcode.OrderStatusErr
case common.ORDER_STATUS_PAYING:
w.CheckCode = errorcode.OrderStatusErr
default:
}
return
}
func (w *PayCheck) GetOrder() {
cond := builder.NewCond()
cond = cond.And(builder.Eq{"out_tread_no": w.WebPayReqs.OutTradeNo}, builder.Eq{"app_id": w.AppCheck.AppId})
cond = cond.And(builder.Eq{"out_tread_no": w.Reqs.OutTradeNo}, builder.Eq{"app_id": w.AppCheck.AppId})
order, code := services.OrderFindOne(&ordersmodel.Orders{}, cond)
if code == errorcode.SystemError {
w.CheckCode = code
@ -67,15 +106,6 @@ func (w *PayCheck) CheckOrder() {
}
if code == errorcode.OrdersExist {
w.OldOrder = order
switch order.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
}
}
return
}

View File

@ -0,0 +1,31 @@
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 {
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 {
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonRefundInfo.Ali)
if err != nil {
return err
}
commonRefundInfo.Ali.AppId = channel.AppId
return nil
}

View File

@ -1,47 +1,79 @@
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 ThirdPayWeb(check *thirdpay.PayCheck) *thirdpay.Pay {
pay := thirdpay.NewPay(check)
// 创建订单
if &check.OldOrder != nil {
pay.CreateOrder()
if pay.PayCode != errorcode.Success {
return pay
}
} else {
pay.Order = check.OldOrder
}
func ThirdPayUrl(check *thirdpay.PayCheck) *thirdpay.Pay {
pay := ThirdPay(check)
// 支付
pay.PayUrl()
return pay
}
func ThirdPayInfoCheck(ctx context.Context, req *front.PayReqs, appCheck *services.AppCheck, ip string) (check *thirdpay.PayCheck) {
check = thirdpay.NewPayCheck(&ctx, req, appCheck, ip)
// 校验表单
check.CheckForm()
if check.CheckCode != errorcode.Success {
return
func NewOrdersResp(db *ordersmodel.Orders) *api.OrdersResp {
return &api.OrdersResp{
OrderNo: db.Id,
OutTreadNo: db.OutTreadNo,
Status: db.Status,
OrderType: db.OrderType,
Amount: db.Amount,
Desc: db.Desc,
CreateTime: db.CreateTime.Format("2006-01-02 15:04:05"),
}
}
// 校验商户
check.CheckMerchant()
if check.CheckCode != errorcode.Success {
return
}
// 校验支付通道
check.CheckPayChannel()
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.NewPay(check)
refund.CreateOrder(common.ORDER_TYPE_REFUND)
refund.Refund()
return
}
func ThirdPay(check *thirdpay.PayCheck) (pay *thirdpay.Pay) {
pay = thirdpay.NewPay(check)
// 创建订单
if &check.OldOrder != nil {
pay.CreateOrder(common.ORDER_TYPE_PAY)
if pay.PayCode != errorcode.Success {
return pay
}
} else {
pay.Order = check.OldOrder
}
return
}

View File

@ -1,4 +1,4 @@
package notify
package thirdpay_notify
import (
"PaymentCenter/app/constants/common"
@ -15,7 +15,7 @@ import (
type OrderNotify struct {
order *ordersmodel.Orders
code int
Code int
app *appmodel.App
OrderId int64
@ -52,9 +52,9 @@ func NewOrderNotifyWithHandle(orderId int64, Status int, actualAmount int, msg s
Status: Status,
ActualAmount: actualAmount,
Msg: msg,
code: errorcode.Success,
Code: errorcode.Success,
}
return orderNotify.handle()
return orderNotify.Handle()
}
func (o *OrderNotify) NotifyRespFail(errorCode int) *OrderNotifyResp {
@ -66,27 +66,27 @@ func (o *OrderNotify) NotifyRespFail(errorCode int) *OrderNotifyResp {
}
}
func (o *OrderNotify) handle() (res *OrderNotifyResp) {
func (o *OrderNotify) Handle() (res *OrderNotifyResp) {
o.checkOrder()
if o.code != errorcode.Success {
return o.NotifyRespFail(o.code)
if o.Code != errorcode.Success {
return o.NotifyRespFail(o.Code)
}
o.checkApp()
if o.code != errorcode.Success {
return o.NotifyRespFail(o.code)
if o.Code != errorcode.Success {
return o.NotifyRespFail(o.Code)
}
o.updateOrder()
if o.code != errorcode.Success {
return o.NotifyRespFail(o.code)
if o.Code != errorcode.Success {
return o.NotifyRespFail(o.Code)
}
o.sendNotify(o.setBody())
if o.code != errorcode.Success {
return o.NotifyRespFail(o.code)
if o.Code != errorcode.Success {
return o.NotifyRespFail(o.Code)
}
return &OrderNotifyResp{
OrderId: o.OrderId,
Send: true,
ErrCode: o.code,
ErrCode: o.Code,
Content: o,
}
}
@ -98,7 +98,7 @@ func (o *OrderNotify) sendNotify(body *OrderNotifySendContent) {
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
o.Code = errorcode.NotifySendFail
}
return
}
@ -120,25 +120,25 @@ func (o *OrderNotify) setBody() *OrderNotifySendContent {
func (o *OrderNotify) updateOrder() {
if _, ok := common.OrderStatusMap[o.Status]; !ok {
o.code = errorcode.OrderStatusErr
o.Code = errorcode.OrderStatusErr
return
}
o.order.Status = o.Status
o.code = services.OrderUpdate(o.order, "status")
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 {
o.app, o.Code = services.AppFindOne(entities.IdRequest{Id: o.order.AppId})
if o.Code != errorcode.Success {
return
}
if o.app.DeleteTime.IsZero() {
o.code = errorcode.AppDisabled
o.Code = errorcode.AppDisabled
return
}
if o.app.NotifyUrl == "" {
o.code = errorcode.AppNotifyUrlNotFound
o.Code = errorcode.AppNotifyUrlNotFound
return
}
@ -149,16 +149,16 @@ 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.Success {
o.order, o.Code = services.OrderFindOne(&ordersmodel.Orders{}, cond)
if o.Code != errorcode.Success {
return
}
if o.order.DeleteTime.IsZero() {
o.code = errorcode.OrderIsDelete
o.Code = errorcode.OrderIsDelete
return
}
if o.order.Status != common.ORDER_STATUS_PAYING {
o.code = errorcode.OrderStatusErr
o.Code = errorcode.OrderStatusErr
return
}
return

View File

@ -1,10 +0,0 @@
package types
type PayResp struct {
OrderNo int64 `json:"order_no"`
OrderType int `json:"out_trade_no"`
Amount int `json:"order_type"`
Desc string `json:"amount"`
IsNewCreate bool `json:"is_new_create"`
Status int `json:"status"`
}

View File

@ -0,0 +1,8 @@
package types
import "PaymentCenter/app/http/entities/front"
type Reqs struct {
front.PayCommonReqBody
OutTradeNo string `json:"out_trade_no"`
}

View File

@ -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
}

View File

@ -1,9 +1,13 @@
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"
@ -99,7 +103,43 @@ func ALiCallBack(notifyReq gopay.BodyMap, aliConfig AliPay) error {
return err
}
// todo 拼装数据触发下游回调,数据待定
// 拼装数据触发下游回调,触发下游回调
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 := ""
saveLog(int64(orderId), common.THIRD_ORDER_TYPE_CALL_BACK, string(payCallback), payParam, string(merchantCallback))
}()
if res.ErrCode != errorcode.Success {
logger.Error(context.Background(), "ALiCallBack 发生错误", fmt.Sprintf("回调时,下游处理订单失败,返回数据为:%s", string(merchantCallback)))
return errors.New("回调时,下游处理订单失败")
}
return nil
}
@ -127,7 +167,7 @@ func ALiOrderQuery(ctx context.Context, aliConfig AliPay, OrderNo string) (PayOr
return PayOrderQueryInfo{}, err
}
// 同步返回验签
ok, err := alipay.VerifySyncSignWithCert(aliConfig.AlipayPublicCert, aliRsp.SignData, aliRsp.Sign)
ok, err := alipay.VerifySyncSignWithCert([]byte(aliConfig.AlipayPublicCert), aliRsp.SignData, aliRsp.Sign)
if err != nil || !ok {
return PayOrderQueryInfo{}, errors.New(fmt.Sprintf("验签失败,失败原因:%s", err.Error()))
}
@ -141,6 +181,7 @@ func ALiOrderQuery(ctx context.Context, aliConfig AliPay, OrderNo string) (PayOr
tradeStateDesc = "交易支付成功"
case "REFUND":
tradeState = "REFUND"
tradeStateDesc = "转入退款"
case "WAIT_BUYER_PAY":
tradeState = "NOTPAY"
tradeStateDesc = "交易创建,等待买家付款"

View File

@ -39,14 +39,6 @@ type AliPay struct {
AlipayPublicCert string `json:"alipay_public_cert"` // 支付宝公钥
}
type AliPayA 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"`

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,13 @@
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"
@ -135,7 +139,40 @@ func WxPayCallBack(notifyReq *wechat.V3NotifyReq, wxConfig WxPay) error {
if err != nil {
return err
}
// todo 返回触发下游回调的格式
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 := ""
saveLog(int64(orderId), common.THIRD_ORDER_TYPE_CALL_BACK, string(payCallback), payParam, string(merchantCallback))
}()
if res.ErrCode != errorcode.Success {
logger.Error(context.Background(), "WxPayCallBack 发生错误", fmt.Sprintf("回调时,下游处理订单失败,返回数据为:%s", string(merchantCallback)))
return errors.New("回调时,下游处理订单失败")
}
return nil
}

View File

@ -108,3 +108,33 @@ func Decrypt(privateKeyPEM string, encryptedDataBase64 string) ([]byte, error) {
return decrypted, 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)
return string(pubPem), string(privPem), nil
}

View File

@ -41,20 +41,6 @@ func encrypt() string {
return base64.StdEncoding.EncodeToString(en)
}
func TestRsaEncryptWithAes(t *testing.T) {
fmt.Printf("%s\n", encryptWithAes())
}
func TestRsaDecryptWithAes(t *testing.T) {
data := "cGuoR6Bmmm9fZr/OAnM54eM6Z7M4ysnRr7TV64rIK6mAkGDzJROwSOY443e7UJmLpwIEn8G5jNk6j8K1scxvIMMdSJZ0QOJREjgzbZfNfuXV0LO1lVNu3uhwVQXN/zMZxBHGIcYQnPWSaOHhNy6yMRPLFNRuIb5FuTx7E6VI5UVZpHk9VLv63QX+6+hQMOiqoif/YyXkAqi2xG+unq4MVq9w5aYMOVzHX1eyMiTeRFRB4iKhf6bCJmVvLMmvjHYKQl3/225R4uXaI8nv7y4IHnK8KVYAnuJE6SvEPeJAjpINrY2CRoNqTYkt7DRS2uz5l7aE+KX8GShV2XlDoM8KZA=="
privateKeyPEM := `-----BEGIN RSA PRIVATE KEY-----
` + PRI + `
-----END RSA PRIVATE KEY-----`
res, err := Decrypt(privateKeyPEM, data)
fmt.Println(string(res), err)
}
func encryptWithAes() string {
data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}"
aes.Encrypt([]byte(data), []byte(aes.TestKey))
@ -69,3 +55,17 @@ func encryptWithAes() string {
return base64.StdEncoding.EncodeToString(en)
}
// 测试生成密钥对
func TestGenerateRSAKey(t *testing.T) {
pub, pri, err := GenerateKey()
data := "{\"pay_channel_id\":8935141660703064070,\"out_trade_no\":\"asdadasdas\",\"order_type\":1,\"amount\":1,\"desc\":\"abc\",\"ext_json\":\"\",\"app_id\":5476377146882523138,\"timestamp\":53612533412643}"
dataJson := []byte(data)
en, err := Encrypt(pub, dataJson)
if err != nil {
panic(err)
}
content := base64.StdEncoding.EncodeToString(en)
res, err := Decrypt(pri, content)
fmt.Println("解密", string(res), err)
}

View File

@ -6,7 +6,7 @@ import (
)
const (
SELF_PRI = "EA7CB6F907A96264D6763F8C46AB96B476538D2ABC880A459E10BE5A1C30013D"
SELF_PRI = "BD13D44C74422F80ADDF54AD2DE2888C4092AF6F61E41FABADA6C47F17574A41"
SELF_PUB = "04363DF574D4FE34EE58FB8A3F7CB08E6CA5EBB3B7335CBAE10A2900551F6450AB3AD25DBC0A76EFA9E6D44D2C51E3027483F7BFD09996457888BAFD1AF673817F"
)
@ -17,7 +17,20 @@ func TestGenerateSM2KeyPair(t *testing.T) {
// Print the private and public keys
fmt.Printf("Private Key: %s\n", privateKey)
fmt.Printf("Public Key: %s", publicKey)
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) {
@ -34,7 +47,7 @@ func TestSM2Decrypt(t *testing.T) {
}
func encrypt() string {
data := "{\"name\":\"张三\",\"sex\":1,\"is_human\":true}"
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)

1
go.mod
View File

@ -82,6 +82,7 @@ require (
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

2
go.sum
View File

@ -443,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=