Merge remote-tracking branch 'origin/feature/rzy/api_1.0' into feature_413_cjh

This commit is contained in:
陈俊宏 2024-08-07 09:00:49 +08:00
commit 75d68a3032
38 changed files with 1130 additions and 89 deletions

View File

@ -60,7 +60,8 @@ func closeOrder() {
PrivateKey: wx.PrivateKey,
}
case common.PAY_CHANNLE_TYPE_ZFB:
ali := backend.AliPayChannel{}
var ali backend.AliPayChannel
req.PayChannel = payCommon.PAY_CHANNLE_TYPE_ZFB
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &ali)
req.Ali = paymentService.AliPay{

View File

@ -29,6 +29,12 @@ const (
ORDER_STATUS_FAILED = 4
ORDER_STATUS_CLOSE = 5
STATUS_ENABLE = 1
STATUS_DISABLED = 2
ORDER_TYPE_PAY = 1
ORDER_TYPE_REFUND = 2
PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信
PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝
@ -39,3 +45,19 @@ const (
THIRD_ORDER_TYPE_CLOSE = 5 // 关闭订单
THIRD_ORDER_TYPE_CALL_BACK = 6 // 支付回调
)
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: "退款",
}

View File

@ -29,12 +29,44 @@ const (
MerchantNotFound = 1100
// app
AppNotFound = 1200
AppDisabled = 1201
AppIpNotAllow = 1202
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
//渠道
PayChannelNotFound = 1300
PayChannelNotFound = 1300
PayChannelNotBuild = 1301
PayChannelExtJsonError = 1302
//订单
OrdersNotFound = 1401
OrdersExist = 1402
OrderTypeNotFount = 1403
OrderIsDelete = 1405
OrderStatusErr = 1406
//请求日志
RequestLogErrors = 1500
RequestLogNotFound = 1501
RequestResponseValid = 1502
//回调
NotifySendFail = 1600
)
var MsgEN = map[int]string{
@ -47,18 +79,50 @@ var MsgEN = map[int]string{
}
var MsgZH = map[int]string{
Success: "请求成功",
ParamError: "参数错误",
NotFound: "数据不存在",
NotAuth: "未经授权",
NotLogin: "未登录",
RequestTimeOut: "请求超时",
MerchantNotFound: "商户不存在",
AppNotFound: "app_id未找到",
AppDisabled: "app通道关闭",
AppIpNotAllow: "ip不在白名单内",
SystemError: "系统错误",
PayChannelNotFound: "支付方式不存在",
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加密失败",
PayChannelNotFound: "支付方式不存在",
PayChannelNotBuild: "支付方式尚未开通",
PayChannelExtJsonError: "支付方式扩展参数错误",
RequestLogErrors: "请求日志错误",
RequestLogNotFound: "未找到日志信息",
RequestResponseValid: "上游返回格式无效",
OrdersNotFound: "未找到订单",
OrdersExist: "订单已存在",
OrderTypeNotFount: "未知的支付方式",
OrderIsDelete: "订单已删除",
OrderStatusErr: "订单状态错误",
NotifySendFail: "回调发送失败",
}
var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH}

View File

@ -1,7 +1,7 @@
package pojo
const (
Rsa int32 = iota + 1
Sm2
Sm4
RSA int32 = iota + 1
SM2
SM4
)

View File

@ -1,6 +0,0 @@
package pojo
const (
STATUS_ENABLE int32 = 1
STATUS_DISABLED int32 = 2
)

View File

@ -45,5 +45,4 @@ func (m *AppRepo) AppFindOne(app *appmodel.App, conn builder.Cond, columns ...st
return nil, sql.ErrNoRows
}
return app, err
}

View File

@ -3,6 +3,7 @@ package data
import (
"PaymentCenter/app/http/entities"
"PaymentCenter/app/models/merchantmodel"
"database/sql"
"xorm.io/builder"
"xorm.io/xorm"
)
@ -41,3 +42,11 @@ func (m *MerchantRepo) MerchantUpdate(merchant *merchantmodel.Merchant, conn bui
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
}

View File

@ -3,6 +3,7 @@ package data
import (
"PaymentCenter/app/http/entities"
"PaymentCenter/app/models/ordersmodel"
"database/sql"
"xorm.io/builder"
"xorm.io/xorm"
)
@ -59,3 +60,11 @@ func (m *OrderRepo) OrdersLeftPayChannelList(conn builder.Cond, pageFilter entit
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
}

View File

@ -3,6 +3,7 @@ package data
import (
"PaymentCenter/app/http/entities"
"PaymentCenter/app/models/paychannelmodel"
"database/sql"
"xorm.io/builder"
"xorm.io/xorm"
)
@ -41,3 +42,11 @@ func (m *PayChannelRepo) PayChannelUpdate(payChannel *paychannelmodel.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
}

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

@ -149,6 +149,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)
@ -164,6 +192,19 @@ 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
}
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

@ -0,0 +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 Pay(c *gin.Context) {
req := controllers.GetRequest(c).(*front.PayReqs)
appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck)
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

@ -108,7 +108,7 @@ 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"`
@ -117,8 +117,9 @@ type OrderRequestLogResponse struct {
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
@ -126,12 +127,13 @@ 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"`
MerchantParam string `json:"merchant_param"`
PayParam string `json:"pay_param"`
MerchantCallback string `json:"merchant_callback"`
}
@ -140,7 +142,7 @@ func (o *OrderThirdLogResponse) ResponseFromDb(db orderthirdpaylogmodel.OrderThi
o.OrderId = db.OrderId
o.PayCallback = db.PayCallback
o.Status = db.Status
o.MerchantParam = db.PayParam
o.PayParam = db.PayParam
o.MerchantCallback = db.MerchantCallback
o.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05")
}

View File

@ -1,12 +1,28 @@
package front
type PayCommonBody struct {
type ApiCommonBody struct {
AppId int64 `json:"app_id" validate:"required"`
Timestamp int64 `json:"timestamp" validate:"required"`
}
type PayWeb struct {
PayCommonBody
PayChannel int64 `json:"private_key_path"`
Delay int64 `json:"delay"` //延时时间
type RequestBody struct {
AppId int64 `json:"app_id" validate:"required"`
Timestamp int64 `json:"timestamp" validate:"required"`
Data string `json:"data" validate:"required"`
}
type PayReqs 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 OrderApiResp struct {
Code int
Msg string
Data interface{}
}

View File

@ -4,12 +4,13 @@ import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/http/controllers"
"PaymentCenter/app/http/entities"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/http/requestmapping"
"PaymentCenter/app/services"
"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.FrontRequestMap[path]
handler = requestmapping.FrontRequestMapBeforeDecrypt[path]
}
if handler == nil {
utils.Log(c, "path", path)
@ -129,35 +131,67 @@ func ValidateRequest() gin.HandlerFunc {
func ValidatePayRequest() gin.HandlerFunc {
return func(c *gin.Context) {
com, err := utils.SonicApiDataToStruct(controllers.GetRequest(c), &front.PayCommonBody{})
var path = c.FullPath()
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
}
comStruct := com.(*front.PayCommonBody)
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信息
app, errCode := services.AppFindOne(entities.IdRequest{Id: comStruct.AppId})
if errCode != errorcode.Success {
controllers.ErrWithCode(c, errCode)
return
}
//检查app可用性
appCheck := services.NewAppCheck(app).Check()
if appCheck.GetCode() != errorcode.Success {
controllers.ErrWithCode(c, appCheck.GetCode())
return
}
//检查白名单
if !appCheck.IpCheck(c.ClientIP()) {
controllers.ErrWithCode(c, appCheck.GetCode())
return
}
appCheck := services.GetAppCheck(requestDataStruct.AppId, c.ClientIP())
//存入请求记录
if appCheck.Code != errorcode.Success {
controllers.ApiRes(c, nil, appCheck.Code)
return
}
//解密
cryptFunc := appCheck.Crypt()
if cryptFunc == nil {
controllers.ApiRes(c, nil, appCheck.GetCode())
}
dataByte, errCode := cryptFunc(appCheck.App).Decrypt(requestDataStruct.Data)
if errCode != apicrypt.CryptNotError {
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.ApiRes(c, nil, appCheck.GetCode())
return
}
//表单验证
handler = requestmapping.FrontRequestMap[path]
v := handler()
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()
}
}

View File

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

View File

@ -6,7 +6,6 @@ package routes
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/http/controllers"
"PaymentCenter/app/http/controllers/backend"
"PaymentCenter/app/http/controllers/front"
"PaymentCenter/app/http/middlewares"
"PaymentCenter/app/http/trace"
@ -56,9 +55,13 @@ func RegisterRoute(router *gin.Engine) {
notify.POST("/wx/:payChannelId", front.WxCallback)
notify.POST("/ali/:payChannelId", front.AliCallback)
}
pay := v1.Group("/pay", middlewares.ValidateRequest(), middlewares.ValidatePayRequest())
{
pay.POST("/do", front.Pay)
}
}
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
pay := v1.Group("pay", middlewares.ValidatePayRequest())
pay.POST("web", backend.MerchantList) // 商户列表
}

View File

@ -15,7 +15,7 @@ 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"`

View File

@ -22,6 +22,7 @@ type Orders struct {
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"`

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

@ -1,16 +1,21 @@
package services
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/constants/pojo"
"PaymentCenter/app/http/entities/front"
"PaymentCenter/app/models/appmodel"
"PaymentCenter/app/services/apicrypt"
"PaymentCenter/app/utils"
"github.com/bytedance/sonic"
"strings"
)
type AppCheck struct {
App *appmodel.App
Code int
AppId int64
Ip string
App *appmodel.App
Code int
}
func NewAppCheck(app *appmodel.App) *AppCheck {
@ -33,11 +38,13 @@ func (a *AppCheck) IpCheck(ip string) bool {
func (a *AppCheck) Check() *AppCheck {
if a.App.Status == pojo.STATUS_DISABLED {
if a.App.Status == common.STATUS_DISABLED {
a.Code = errorcode.AppDisabled
return a
}
if a.App.DeleteTime.Location() == nil {
if !a.App.DeleteTime.IsZero() {
a.Code = errorcode.AppNotFound
return a
}
return a
}
@ -45,3 +52,27 @@ func (a *AppCheck) Check() *AppCheck {
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
}

View File

@ -1,17 +1,43 @@
package apicrypt
import "PaymentCenter/app/models/appmodel"
import (
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/models/appmodel"
"PaymentCenter/app/utils/encrypt/rsa"
)
func NewRsa(app *appmodel.App) ApiDecrypt {
func NewRsa(app *appmodel.App) ApiCrypt {
return &Rsa{
App: app,
}
}
func (r *Rsa) Encrypt(decryptData interface{}) (encryptData string, err error) {
func (r *Rsa) Encrypt(decryptData string) (encryptData []byte, errCode int) {
if r.App.PublicKey == "" {
return nil, errorcode.AppRsaEncryptKeyNotFound
}
publicKeyPEM := `-----BEGIN PUBLIC KEY-----
` + r.App.PublicKey + `
-----END PUBLIC KEY-----`
encryptData, err := rsa.Encrypt(publicKeyPEM, []byte(decryptData))
if err != nil {
return nil, errorcode.AppRsaEncryptFail
}
return
}
func (r *Rsa) Decrypt(encryptData string) (decryptData map[string]interface{}, err error) {
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
}

View File

@ -1,9 +1,39 @@
package apicrypt
func (r *SM2) Encrypt(decryptData interface{}) (encryptData string, err error) {
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(decryptData string) (encryptData []byte, errCode int) {
if r.App.MerchantPublicKey == "" {
return nil, errorcode.AppSM2EncryptKeyNotFound
}
//
encryptDataString, err := sm2.SM2Encrypt(decryptData, r.App.PrivateKey)
if err != nil {
return nil, errorcode.AppSM2EncryptFail
}
encryptData = []byte(encryptDataString)
return
}
func (r *SM2) Decrypt(encryptData string) (decryptData map[string]interface{}, err error) {
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
}

View File

@ -1,9 +1,41 @@
package apicrypt
func (r *SM4) Encrypt(decryptData interface{}) (encryptData string, err error) {
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(decryptData 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, decryptData, "", true)
if err != nil {
return nil, errorcode.AppSM4EncryptFail
}
encryptData = []byte(encryptDataString)
return
}
func (r *SM4) Decrypt(encryptData string) (decryptData map[string]interface{}, err error) {
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
}

View File

@ -1,11 +1,14 @@
package apicrypt
import "PaymentCenter/app/models/appmodel"
import (
"PaymentCenter/app/constants/pojo"
"PaymentCenter/app/models/appmodel"
)
type (
ApiDecrypt interface {
Encrypt(decryptData interface{}) (encryptData string, err error)
Decrypt(encryptData string) (decryptData map[string]interface{}, err error)
ApiCrypt interface {
Encrypt(decryptData string) (encryptData []byte, errCode int)
Decrypt(encryptData string) (decryptData []byte, errCode int)
}
Rsa struct {
@ -20,3 +23,11 @@ type (
App *appmodel.App
}
)
var ApiCryptMap = map[int32]func(app *appmodel.App) ApiCrypt{
pojo.RSA: NewRsa,
pojo.SM2: NewSm2,
pojo.SM4: NewSm4,
}
const CryptNotError = 0

View File

@ -65,7 +65,7 @@ func AppUpdate(app *appmodel.App) (code int) {
} else {
_, err = repo.AppUpdate(app, conn)
}
code = handErr(err)
return
}
@ -99,3 +99,32 @@ func AppFindOne(req entities.IdRequest, col ...string) (row *appmodel.App, code
}
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
}
//检查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
}

View File

@ -1,10 +1,12 @@
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"
)
@ -65,3 +67,28 @@ func MerchantDelete(req entities.IdRequest) (code int) {
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
}
if !merchantInfo.DeleteTime.IsZero() {
return nil, errorcode.MerchantNotFound
}
return
}

View File

@ -1,12 +1,14 @@
package services
import (
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/data"
"PaymentCenter/app/http/entities/backend"
"PaymentCenter/app/models/orderrequestlogmodel"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/models/orderthirdpaylogmodel"
"PaymentCenter/app/models/paychannelmodel"
"database/sql"
"xorm.io/builder"
)
@ -72,3 +74,42 @@ func OrderLogsList(req backend.OrderLogsListRequest) (requestLog []orderrequestl
return orderLogList, thirdLogList, 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.OrdersExist
}
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
}

View File

@ -7,6 +7,7 @@ import (
"PaymentCenter/app/http/entities/backend"
"PaymentCenter/app/models/merchantmodel"
"PaymentCenter/app/models/paychannelmodel"
"database/sql"
"xorm.io/builder"
)
@ -92,3 +93,27 @@ func PayChannelGet(payChannel *paychannelmodel.PayChannel) (code int) {
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.MerchantNotFound
}
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
}
if !channelInfo.DeleteTime.IsZero() {
return nil, errorcode.PayChannelNotFound
}
return
}

View File

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

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,164 @@
package notify
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/http/entities"
"PaymentCenter/app/models/appmodel"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/services"
"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
ErrCode 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"`
OutTreadNo string `json:"out_tread_no"`
CompleteTime time.Time `json:"complete_time"`
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, errCode int, actualAmount int, msg string) *OrderNotifyResp {
orderNotify := &OrderNotify{
OrderId: orderId,
ErrCode: errCode,
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.ErrCode,
Content: o,
}
}
func (o *OrderNotify) sendNotify(body *OrderNotifySendContent) {
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
}
return
}
func (o *OrderNotify) setBody() *OrderNotifySendContent {
return &OrderNotifySendContent{
OrderId: o.OrderId,
OutTreadNo: o.order.OutTreadNo,
CompleteTime: o.CompleteTime,
Status: o.order.Status,
Msg: o.Msg,
ErrCode: o.ErrCode,
AppId: o.order.AppId,
ChannelId: o.order.PayChannelId,
MerchantId: o.order.MerchantId,
}
}
func (o *OrderNotify) updateOrder() {
if o.ErrCode == errorcode.Success {
o.order.Status = common.ORDER_STATUS_FAILED
} else {
o.order.Status = common.ORDER_STATUS_PAYED
}
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.DeleteTime.IsZero() {
o.code = errorcode.AppDisabled
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.Success {
return
}
if o.order.DeleteTime.IsZero() {
o.code = errorcode.OrderIsDelete
return
}
if o.order.Status != common.ORDER_STATUS_PAYING {
o.code = errorcode.OrderStatusErr
return
}
return
}

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

@ -39,6 +39,14 @@ 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"`

View File

@ -4,7 +4,6 @@ import (
"encoding/base64"
"fmt"
"testing"
"time"
)
const (
@ -14,8 +13,8 @@ const (
)
func TestRsaEncrypt(t *testing.T) {
fmt.Println(time.Now().UnixNano() / (1000000))
//fmt.Printf("%s\n", encrypt())
fmt.Printf("%s\n", encrypt())
}
func TestRsaDecrypt(t *testing.T) {
@ -28,7 +27,7 @@ func TestRsaDecrypt(t *testing.T) {
}
func encrypt() string {
data := "{\"name\":\"张三\",\"sex\":1,\"is_human\":true}"
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 + `