<feat>支付接口

This commit is contained in:
Rzy 2024-08-06 16:53:59 +08:00
parent 548491c1f1
commit 943c3401c6
28 changed files with 486 additions and 232 deletions

View File

@ -125,7 +125,7 @@ func queryOrder() {
// 更新订单状态 todo
orderUpdate := ordersmodel.Orders{
Id: orderInfo.Id,
Status: status,
Status: int32(status),
}
session := ordersmodel.GetInstance().GetDb().NewSession()

View File

@ -56,8 +56,11 @@ const (
OrdersNotFound = 1401
OrdersExist = 1402
OrderTypeNotFount = 1403
//网页支付
RequestLogErrors = 1500
//请求日志
RequestLogErrors = 1500
RequestLogNotFound = 1501
RequestResponseValid = 1502
)
var MsgEN = map[int]string{
@ -101,7 +104,9 @@ var MsgZH = map[int]string{
PayChannelNotBuild: "支付方式尚未开通",
PayChannelExtJsonError: "支付方式扩展参数错误",
RequestLogErrors: "请求日志错误",
RequestLogErrors: "请求日志错误",
RequestLogNotFound: "未找到日志信息",
RequestResponseValid: "上游返回格式无效",
OrdersNotFound: "未找到订单",
OrdersExist: "订单已存在",

102
app/http/controllers/api.go Normal file
View File

@ -0,0 +1,102 @@
package controllers
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/models/orderrequestlogmodel"
"PaymentCenter/app/services"
"PaymentCenter/app/utils"
"PaymentCenter/config"
"encoding/json"
"github.com/gin-gonic/gin"
"net/http"
)
func ApiRes(c *gin.Context, data interface{}, code int, msg ...string) {
var log_id int64
message := ""
if utils.IsNil(data) {
data = struct{}{}
}
if len(msg) > 0 {
message = msg[0]
} else {
message = errorcode.GetMsg(code, "")
}
log, exists := GetApiLogId(c)
if exists {
log_id = log.(int64)
dataByte, _ := json.Marshal(data)
status := common.STATUS_ENABLE
if code == errorcode.Success {
status = common.STATUS_DISABLED
}
services.RequestLogUpdate(&orderrequestlogmodel.OrderRequestLog{
Id: log_id,
MerchantResponse: string(dataByte),
Status: status,
})
}
if code == errorcode.Success {
ApiSuccess(c, data, log_id, message)
} else {
ApiError(c, code, log_id, message)
}
}
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()
}

View File

@ -200,6 +200,11 @@ func GetAppCheckInfo(c *gin.Context) interface{} {
return request
}
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, "")

View File

@ -1,16 +1,32 @@
package front
import (
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/http/controllers"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/services"
"PaymentCenter/app/services/thirdpay"
"github.com/gin-gonic/gin"
)
func WebPay(c *gin.Context) {
req := controllers.GetRequest(c).(*front.PayWebReqs)
func Pay(c *gin.Context) {
req := controllers.GetRequest(c).(*front.PayReqs)
appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck)
code := services.ThirdPayWeb(c.Request.Context(), req, appCheckInfo, c.ClientIP())
controllers.ErrWithCode(c, code)
check := thirdpay.ThirdPayCheck(c.Request.Context(), req, appCheckInfo, c.ClientIP())
if check.CheckCode != errorcode.Success {
if check.CheckCode == errorcode.OrdersExist {
//订单已存在,直接返回订单信息
controllers.ApiRes(c, thirdpay.PayCallBack(check.OldOrder, false), errorcode.Success)
return
}
controllers.ApiRes(c, nil, check.CheckCode)
return
}
payInfo := thirdpay.ThirdPayWeb(check)
if payInfo.PayCode != errorcode.Success {
controllers.ApiRes(c, nil, payInfo.PayCode)
return
}
controllers.ApiRes(c, thirdpay.PayCallBack(payInfo.Order, true), errorcode.Success)
return
}

View File

@ -70,8 +70,8 @@ type OrdersResponse struct {
PayChannelId int64 `json:"pay_channel_id"`
AppId int64 `json:"app_id"`
OutTreadNo string `json:"out_tread_no"`
Status int `json:"status"`
OrderType int `json:"order_type"`
Status int32 `json:"status"`
OrderType int32 `json:"order_type"`
Amount int `json:"amount"`
IpAddress string `json:"ip_address"`
MerchantRequest string `json:"merchant_request"`
@ -110,17 +110,18 @@ type OrderLogsListRequest struct {
type OrderRequestLogResponse struct {
Id int64 `json:"id"`
IpAddress string `json:"ip_address"`
OrderId int64 `json:"order_id"`
Url string `json:"url"`
MerchantRequest string `json:"merchant_request"`
MerchantResponse string `json:"merchant_response"`
CreateTime string `json:"create_time"`
Status int `json:"status"`
Status int32 `json:"status"`
}
func (o *OrderRequestLogResponse) ResponseFromDb(db orderrequestlogmodel.OrderRequestLog) {
o.Id = db.Id
o.OrderId = db.OrderId
o.IpAddress = db.IpAddress
o.Url = db.URL
o.Status = db.Status
o.MerchantRequest = db.MerchantRequest
o.MerchantResponse = db.MerchantResponse
@ -128,8 +129,9 @@ func (o *OrderRequestLogResponse) ResponseFromDb(db orderrequestlogmodel.OrderRe
}
type OrderThirdLogResponse struct {
Id int64 `json:"id"`
OrderId int64 `json:"order_id"`
Id int64 `json:"id"`
OrderId int64 `json:"order_id"`
CreateTime string `json:"create_time"`
PayCallback string `json:"pay_callback"`
Status int `json:"status"`

View File

@ -11,7 +11,7 @@ type RequestBody struct {
Data string `json:"data" validate:"required"`
}
type PayWebReqs struct {
type PayReqs struct {
ApiCommonBody
PayChannelId int64 `json:"pay_channel_id" validate:"required" label:"支付渠道"`
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
@ -20,3 +20,9 @@ type PayWebReqs struct {
ExtJson string `json:"ext_json" label:"扩展参数"`
Desc string `json:"desc" validate:"max=100" label:"商品描述"`
}
type OrderApiResp struct {
Code int
Msg string
Data interface{}
}

View File

@ -10,6 +10,7 @@ import (
"PaymentCenter/app/services/apicrypt"
"PaymentCenter/app/utils"
"PaymentCenter/config"
"encoding/json"
"github.com/gin-gonic/gin"
"strings"
)
@ -104,10 +105,11 @@ 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.FrontRequest()
handler = requestmapping.FrontRequestMapBeforeDecrypt[path]
}
if handler == nil {
utils.Log(c, "path", path)
@ -133,40 +135,45 @@ func ValidatePayRequest() gin.HandlerFunc {
var handler func() interface{}
requestData, err := utils.SonicApiDataToStruct(controllers.GetRequest(c), &front.RequestBody{})
if err != nil {
controllers.ErrWithCode(c, errorcode.ParamError)
controllers.ApiRes(c, nil, errorcode.ParamError)
return
}
requestDataStruct := requestData.(*front.RequestBody)
//判断时间
//now := time.Now().UnixNano() / 1000000
//if comStruct.Timestamp > now || (config.GetConf().TimeOut != 0 && (now-comStruct.Timestamp) > config.GetConf().TimeOut) {
// controllers.ErrWithCode(c, errorcode.RequestTimeOut)
//if requestDataStruct.Timestamp > now || (config.GetConf().TimeOut != 0 && (now-requestDataStruct.Timestamp) > config.GetConf().TimeOut) {
// controllers.ApiRes(c, nil, errorcode.RequestTimeOut)
// return
//}
//获取app信息
appCheck := services.AppGetAndCheck(&services.AppCheck{
AppId: requestDataStruct.AppId,
Ip: c.ClientIP(),
Code: errorcode.Success,
})
appCheck := services.GetAppCheck(requestDataStruct.AppId, c.ClientIP())
//存入请求记录
if appCheck.Code != errorcode.Success {
controllers.ErrWithCode(c, appCheck.Code)
controllers.ApiRes(c, nil, appCheck.Code)
return
}
//解密
cryptFunc := appCheck.Crypt()
if cryptFunc == nil {
controllers.ErrWithCode(c, appCheck.GetCode())
controllers.ApiRes(c, nil, appCheck.GetCode())
}
dataByte, errCode := cryptFunc(appCheck.App).Decrypt(requestDataStruct.Data)
if errCode != apicrypt.CryptNotError {
controllers.ErrWithCode(c, errCode)
controllers.ApiRes(c, nil, errCode)
return
}
//记录请求日志
id, code := services.AddRequestLog(dataByte, c.ClientIP(), path)
if code != errorcode.Success {
controllers.ApiRes(c, nil, errCode)
}
c.Set("log", id)
//检查解密后的数据是否与请求一致
reCheck := appCheck.ReCheckAfterDecrypt(dataByte, requestDataStruct)
if !reCheck {
controllers.ErrWithCode(c, appCheck.GetCode())
controllers.ApiRes(c, nil, appCheck.GetCode())
return
}
//表单验证
@ -175,10 +182,15 @@ func ValidatePayRequest() gin.HandlerFunc {
msg, err := controllers.ValidApiData(dataByte, v)
if err != nil {
utils.Log(c, "参数错误", "path=", path, "err=", err.Error(), "msg=", msg)
controllers.Error(c, errorcode.ParamError, msg...)
controllers.ApiRes(c, nil, errorcode.ParamError, msg...)
c.Abort()
}
c.Set("request", dataByte)
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()
}

View File

@ -6,11 +6,9 @@ import (
)
var FrontRequestMap = map[string]func() interface{}{
common.FRONT_V1 + "/pay/web": func() interface{} { return new(front.PayWebResp) },
common.FRONT_V1 + "/pay/do": func() interface{} { return new(front.PayReqs) },
}
func FrontRequest() func() interface{} {
return func() interface{} {
return new(front.RequestBody)
}
var FrontRequestMapBeforeDecrypt = map[string]func() interface{}{
common.FRONT_V1 + "/pay/do": func() interface{} { return new(front.RequestBody) },
}

View File

@ -58,7 +58,7 @@ func RegisterRoute(router *gin.Engine) {
pay := v1.Group("/pay", middlewares.ValidateRequest(), middlewares.ValidatePayRequest())
{
pay.POST("/web", front.WebPay)
pay.POST("/do", front.Pay)
}
}

View File

@ -15,12 +15,12 @@ var (
type OrderRequestLog struct {
Id int64
IpAddress string `xorm:"'ip_address' varchar(16)"`
OrderId int64 `xorm:"'order_id' bigint(20)"`
URL string `xorm:"'url' varchar(20)"`
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"`
Status int32 `xorm:"'status' TINYINT"`
}
// 表名

View File

@ -24,7 +24,7 @@ type Orders struct {
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"`
Status int32 `xorm:"'status' TINYINT"`
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
}

View File

@ -16,7 +16,7 @@ type PayChannel struct {
Id int64
PayName string `xorm:"'pay_name' varchar(128)"`
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
ChannelType int `xorm:"'channel_type' int(11)"`
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"`

View File

@ -42,7 +42,7 @@ func (a *AppCheck) Check() *AppCheck {
a.Code = errorcode.AppDisabled
return a
}
if a.App.DeleteTime.Location() == nil {
if !a.App.DeleteTime.IsZero() {
a.Code = errorcode.AppNotFound
return a
}

View File

@ -100,22 +100,31 @@ func AppFindOne(req entities.IdRequest, col ...string) (row *appmodel.App, code
return row, errorcode.Success
}
func AppGetAndCheck(appCheckIn *AppCheck) (appCheckOut *AppCheck) {
func CheckApp(appCheckIn *AppCheck) {
errCode := errorcode.Success
appCheckOut.App, errCode = AppFindOne(entities.IdRequest{Id: appCheckIn.AppId})
appCheckIn.App, errCode = AppFindOne(entities.IdRequest{Id: appCheckIn.AppId})
if errCode != errorcode.Success {
appCheckOut.Code = errCode
return
appCheckIn.Code = errCode
}
//检查app可用性
appCheckOut = appCheckIn.Check()
if appCheckOut.GetCode() != errorcode.Success {
appCheckIn.Check()
if appCheckIn.GetCode() != errorcode.Success {
return
}
//检查白名单
if appCheckIn.Ip != "" && !appCheckOut.IpCheck(appCheckIn.Ip) {
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
}

View File

@ -86,7 +86,8 @@ func GetAndCheckMerchant(merchant *merchantmodel.Merchant, conn builder.Cond, co
if code != errorcode.Success {
return nil, code
}
if merchantInfo.DeleteTime.Location() != nil {
if !merchantInfo.DeleteTime.IsZero() {
return nil, errorcode.MerchantNotFound
}
return

View File

@ -1,7 +1,6 @@
package services
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/data"
"PaymentCenter/app/http/entities/backend"
@ -78,8 +77,7 @@ func OrderLogsList(req backend.OrderLogsListRequest) (requestLog []orderrequestl
func OrderCreate(orderIn *ordersmodel.Orders) (orderOut *ordersmodel.Orders, code int) {
repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb())
orderId, err := repo.OrderInsertOne(orderIn)
orderIn.Id = orderId
_, err := repo.OrderInsertOne(orderIn)
code = handErr(err)
return orderIn, code
}
@ -97,9 +95,7 @@ func OrderFindOne(order *ordersmodel.Orders, conn builder.Cond, col ...string) (
return orderInfo, errorcode.OrdersExist
}
func HadSameValueOrder(order *ordersmodel.Orders) (exist bool, code int) {
conn := builder.NewCond()
conn = conn.And(builder.Neq{"Status": common.ORDER_STATUS_CLOSE})
func PayOrderCheckRepeat(order *ordersmodel.Orders, conn builder.Cond) (exist bool, code int) {
_, code = OrderFindOne(order, conn)
if code != errorcode.OrdersNotFound {
return false, errorcode.Success

View File

@ -1,45 +0,0 @@
package services
import (
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/services/thirdpay"
"context"
)
func ThirdPayWeb(ctx context.Context, req *front.PayWebReqs, appCheck *AppCheck, ip string) (code int) {
pay := thirdpay.NewWebPay(&ctx, req, appCheck, ip)
// 校验表单
pay.CheckForm()
if pay.PayCode != errorcode.Success {
code = pay.PayCode
return
}
// 校验商户
pay.CheckMerchant()
if pay.PayCode != errorcode.Success {
code = pay.PayCode
return
}
// 校验支付通道
pay.CheckPayChannel()
if pay.PayCode != errorcode.Success {
code = pay.PayCode
return
}
// 校验订单
pay.CheckOrder()
if pay.PayCode != errorcode.Success {
code = pay.PayCode
return
}
// 创建订单
pay.CreateOrder()
if pay.PayCode != errorcode.Success {
code = pay.PayCode
return
}
// 支付
pay.Pay()
return
}

View File

@ -107,12 +107,12 @@ func PayChannelFindOne(channel *paychannelmodel.PayChannel, conn builder.Cond, c
return channelInfo, errorcode.Success
}
func GetAndCheckPayChannel(channel *paychannelmodel.PayChannel, conn builder.Cond, col ...string) (merchantInfo *paychannelmodel.PayChannel, code int) {
merchantInfo, code = PayChannelFindOne(channel, conn, col...)
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
}
if merchantInfo.DeleteTime.Location() != nil {
if !channelInfo.DeleteTime.IsZero() {
return nil, errorcode.PayChannelNotFound
}
return

View File

@ -1,14 +1,43 @@
package services
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/data"
"PaymentCenter/app/models/orderrequestlogmodel"
"xorm.io/builder"
)
func RequestLogCreate(log *orderrequestlogmodel.OrderRequestLog) (code int) {
func RequestLogCreate(log *orderrequestlogmodel.OrderRequestLog) (*orderrequestlogmodel.OrderRequestLog, int) {
db := orderrequestlogmodel.GetInstance().GetDb()
repo := data.NewOrderRequestLogRepo(db)
_, err := repo.OrderRequestLogInsertOne(log)
code = handErr(err)
return
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
}

View File

@ -0,0 +1,64 @@
package do
import (
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/services"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/third/paymentService"
)
type Pay struct {
paycheck *PayCheck
Order *ordersmodel.Orders
PayCode int
}
func NewPay(paycheck *PayCheck) *Pay {
return &Pay{
paycheck: paycheck,
PayCode: errorcode.Success,
}
}
func (w *Pay) CreateOrder() {
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,
},
)
}
func (w *Pay) Pay() {
var (
payFunc func(commonPayInfo *paymentService.PayOrderRequest, ExtJson string) error
ok bool
)
thirdPay := &paymentService.PayOrderRequest{
PayChannelId: w.paycheck.WebPayReqs.PayChannelId,
OrderId: w.Order.Id,
ChannelType: w.paycheck.Channel.ChannelType,
Description: w.Order.Desc,
Amount: w.Order.Amount,
PayerClientIp: w.paycheck.AppCheck.Ip,
}
if payFunc, ok = PayWayList[w.paycheck.Channel.ChannelType]; !ok {
w.PayCode = errorcode.PayChannelNotBuild
return
}
err := payFunc(thirdPay, w.paycheck.Channel.ExtJson)
if err != nil {
w.PayCode = errorcode.PayChannelExtJsonError
return
}
res := paymentService.PaymentService(*w.paycheck.ctx, *thirdPay)
w.PayCode = res.Code
return
}

View File

@ -0,0 +1,69 @@
package do
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/services"
"xorm.io/builder"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/models/merchantmodel"
"PaymentCenter/app/models/orderrequestlogmodel"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/models/paychannelmodel"
"context"
)
type PayCheck struct {
ctx *context.Context
WebPayReqs *front.PayReqs
AppCheck *services.AppCheck
RequestLog *orderrequestlogmodel.OrderRequestLog
Channel *paychannelmodel.PayChannel
Merchant *merchantmodel.Merchant
OldOrder *ordersmodel.Orders
CheckCode int
}
func NewPayCheck(ctx *context.Context, reqs *front.PayReqs, 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,
}
}
func (w *PayCheck) CheckForm() {
if _, ok := common.OrderTypeList[w.WebPayReqs.OrderType]; !ok { //判断是否是支持的支付渠道
w.CheckCode = errorcode.PayChannelNotFound
return
}
}
func (w *PayCheck) CheckPayChannel() {
conn := builder.NewCond()
conn = conn.And(builder.Eq{"id": w.WebPayReqs.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) CheckOrder() {
cond := builder.NewCond()
cond = cond.And(builder.Eq{"out_tread_no": w.WebPayReqs.OutTradeNo}, builder.Eq{"app_id": w.AppCheck.AppId}, builder.Neq{"status": common.ORDER_STATUS_CLOSE})
order, code := services.OrderFindOne(&ordersmodel.Orders{}, cond)
if code == errorcode.OrdersExist {
w.OldOrder = order
w.CheckCode = code
}
return
}

View File

@ -0,0 +1,28 @@
package do
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/third/paymentService"
"github.com/bytedance/sonic"
)
var PayWayList = map[int]func(commonPayInfo *paymentService.PayOrderRequest, ExtJson string) error{
common.PAY_CHANNEL_WECHAT_H5: WechatH5,
common.PAY_CHANNEL_ALIPAY_WEB: AlipayWeb,
}
func WechatH5(commonPayInfo *paymentService.PayOrderRequest, ExtJson string) error {
err := sonic.Unmarshal([]byte(ExtJson), &commonPayInfo.Wx)
if err != nil {
return err
}
return nil
}
func AlipayWeb(commonPayInfo *paymentService.PayOrderRequest, ExtJson string) error {
err := sonic.Unmarshal([]byte(ExtJson), &commonPayInfo.Ali)
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,62 @@
package thirdpay
import (
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/services"
thirdpay "PaymentCenter/app/services/thirdpay/do"
"PaymentCenter/app/services/thirdpay/types"
"context"
)
func ThirdPayWeb(check *thirdpay.PayCheck) *thirdpay.Pay {
pay := thirdpay.NewPay(check)
// 创建订单
pay.CreateOrder()
if pay.PayCode != errorcode.Success {
return pay
}
// 支付
pay.Pay()
return pay
}
func ThirdPayCheck(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
}
// 校验订单
check.CheckOrder()
if check.CheckCode != errorcode.Success {
return
}
// 校验商户
check.CheckMerchant()
if check.CheckCode != errorcode.Success {
return
}
// 校验支付通道
check.CheckPayChannel()
if check.CheckCode != errorcode.Success {
return
}
return
}
func PayCallBack(order *ordersmodel.Orders, isNew bool) *types.PayResp {
res := &types.PayResp{
OrderNo: order.Id,
OrderType: order.OrderType,
Amount: order.Amount,
Desc: order.Desc,
IsNewCreate: isNew,
Status: order.Status,
}
return res
}

View File

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

View File

@ -1,123 +0,0 @@
package thirdpay
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/services"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/models/merchantmodel"
"PaymentCenter/app/models/orderrequestlogmodel"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/models/paychannelmodel"
"PaymentCenter/app/third/paymentService"
"context"
"github.com/bytedance/sonic"
)
type WebPay struct {
ctx *context.Context
WebPayReqs *front.PayWebReqs
AppCheck *services.AppCheck
Order *ordersmodel.Orders
Channel *paychannelmodel.PayChannel
Merchant *merchantmodel.Merchant
PayCode int
}
func NewWebPay(ctx *context.Context, reqs *front.PayWebReqs, appCheck *services.AppCheck, ip string) *WebPay {
if appCheck == nil {
appCheck = services.AppGetAndCheck(&services.AppCheck{
AppId: reqs.AppId,
Ip: ip,
Code: errorcode.Success,
})
}
return &WebPay{
ctx: ctx,
WebPayReqs: reqs,
AppCheck: appCheck,
PayCode: appCheck.Code,
}
}
func (w *WebPay) CheckForm() {
if _, ok := common.OrderTypeList[w.WebPayReqs.OrderType]; !ok { //判断是否是支持的支付渠道
w.PayCode = errorcode.PayChannelNotFound
return
}
}
func (w *WebPay) AddPayLog() {
requestJson, err := sonic.Marshal(w.WebPayReqs)
if err != nil {
w.PayCode = errorcode.RequestLogErrors
return
}
code := services.RequestLogCreate(&orderrequestlogmodel.OrderRequestLog{
IpAddress: w.AppCheck.Ip,
MerchantRequest: string(requestJson),
})
w.PayCode = code
return
}
func (w *WebPay) CheckPayChannel() {
w.Channel, w.PayCode = services.GetAndCheckPayChannel(&paychannelmodel.PayChannel{Id: w.WebPayReqs.PayChannelId}, nil)
}
func (w *WebPay) CheckMerchant() {
w.Merchant, w.PayCode = services.GetAndCheckMerchant(&merchantmodel.Merchant{Id: w.AppCheck.App.MerchantId}, nil)
}
func (w *WebPay) CheckOrder() {
exist, code := services.HadSameValueOrder(&ordersmodel.Orders{OutTreadNo: w.WebPayReqs.OutTradeNo})
if exist {
w.PayCode = code
}
}
func (w *WebPay) CreateOrder() {
w.Order, w.PayCode = services.OrderCreate(&ordersmodel.Orders{
MerchantId: w.Merchant.Id,
PayChannelId: w.Channel.Id,
AppId: w.Channel.Id,
OutTreadNo: w.WebPayReqs.OutTradeNo,
OrderType: w.WebPayReqs.OrderType,
Amount: w.WebPayReqs.Amount,
ExtJson: w.WebPayReqs.ExtJson,
Desc: w.WebPayReqs.Desc,
},
)
}
func (w *WebPay) Pay() {
thirdPay := &paymentService.PayOrderRequest{
PayChannelId: w.WebPayReqs.PayChannelId,
OrderId: w.Order.Id,
ChannelType: w.Channel.ChannelType,
Description: w.Order.Desc,
Amount: w.Order.Amount,
PayerClientIp: w.AppCheck.Ip,
}
//{"api_v_3_key": "131231231", "app_id": "123", "mch_id": "123123", "private_key": "2131312", "serial_no": "123213213"}
switch w.WebPayReqs.OrderType {
case common.PAY_CHANNEL_WECHAT_H5:
var wx paymentService.WxPay
err := sonic.Unmarshal([]byte(w.Channel.ExtJson), &wx)
if err != nil {
w.PayCode = errorcode.PayChannelExtJsonError
return
}
wx.AppId = w.Channel.AppId
case common.PAY_CHANNEL_ALIPAY_WEB:
//{"ali_public_key": "123", "private_key_path": "123", "sign_type": "123"}
//thirdPay.Ali = &paymentService.AliPay{}
default:
w.PayCode = errorcode.PayChannelNotBuild
return
}
_ = paymentService.PaymentService(*w.ctx, *thirdPay)
return
}

View File

@ -34,6 +34,14 @@ type AliPay struct {
AlipayPublicCert []byte `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"`

View File

@ -27,7 +27,7 @@ func TestRsaDecrypt(t *testing.T) {
}
func encrypt() string {
data := "{\"app_id\":5476377146882523138,\"name\":\"张三\",\"sex\":1,\"is_human\":true,\"timestamp\":53612533412643}"
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)
pub := `-----BEGIN PUBLIC KEY-----
` + PUB + `