From 13dce2d1c31963ee7f5c1267d19a145f258a5dd0 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Mon, 5 Aug 2024 10:55:35 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E5=8A=A0=E5=AF=86=E8=A7=A3=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/errorcode/error_code.go | 33 +++++++++++++++++++++--- app/constants/pojo/app.go | 6 ++--- app/http/entities/front/pay.go | 6 +++++ app/http/middlewares/base.go | 18 +++++++++++--- app/services/api_request_valid.go | 14 +++++++++++ app/services/apicrypt/rsa.go | 29 ++++++++++++++++++--- app/services/apicrypt/sm2.go | 34 +++++++++++++++++++++++-- app/services/apicrypt/sm4.go | 36 +++++++++++++++++++++++++-- app/services/apicrypt/types.go | 17 ++++++++++--- 9 files changed, 171 insertions(+), 22 deletions(-) diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 8df0f99..a4838df 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -29,9 +29,21 @@ const ( MerchantNotFound = 1100 // app - AppNotFound = 1200 - AppDisabled = 1201 - AppIpNotAllow = 1202 + AppNotFound = 1200 + AppDisabled = 1201 + AppIpNotAllow = 1202 + AppRsaDecryptKeyNotFound = 1300 + AppRsaDecryptFail = 1301 + AppRsaEncryptKeyNotFound = 1302 + AppRsaEncryptFail = 1303 + AppSM2DecryptKeyNotFound = 1310 + AppSM2DecryptFail = 1311 + AppSM2EncryptKeyNotFound = 1312 + AppSM2EncryptFail = 1313 + AppSM4DecryptKeyNotFound = 1320 + AppSM4DecryptFail = 1321 + AppSM4EncryptKeyNotFound = 1322 + AppSM4EncryptFail = 1323 ) var MsgEN = map[int]string{ @@ -54,6 +66,21 @@ var MsgZH = map[int]string{ AppNotFound: "app_id未找到", AppDisabled: "app通道关闭", AppIpNotAllow: "ip不在白名单内", + + AppRsaDecryptKeyNotFound: "密匙缺失,无法进行Rsa解密", + AppRsaDecryptFail: "Rsa解密失败", + AppRsaEncryptKeyNotFound: "密匙缺失,无法进行Rsa加密", + AppRsaEncryptFail: "Rsa加密失败", + + AppSM2DecryptKeyNotFound: "密匙缺失,无法进行sm2解密", + AppSM2DecryptFail: "sm2解密失败", + AppSM2EncryptKeyNotFound: "密匙缺失,无法进行sm2加密", + AppSM2EncryptFail: "sm2加密失败", + + AppSM4DecryptKeyNotFound: "密匙缺失,无法进行sm4解密", + AppSM4DecryptFail: "sm4解密失败", + AppSM4EncryptKeyNotFound: "密匙缺失,无法进行sm4加密", + AppSM4EncryptFail: "sm4加密失败", } var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH} diff --git a/app/constants/pojo/app.go b/app/constants/pojo/app.go index 29f0239..8132200 100644 --- a/app/constants/pojo/app.go +++ b/app/constants/pojo/app.go @@ -1,7 +1,7 @@ package pojo const ( - Rsa int32 = iota + 1 - Sm2 - Sm4 + RSA int32 = iota + 1 + SM2 + SM4 ) diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index f3dca7a..7efc930 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -5,6 +5,12 @@ type PayCommonBody struct { Timestamp int64 `json:"timestamp" validate:"required"` } +type RequestBody struct { + AppId int64 `json:"app_id" validate:"required"` + Timestamp int64 `json:"timestamp" validate:"required"` + Data string `json:"data" validate:"required"` +} + type PayWeb struct { PayCommonBody PayChannel int64 `json:"private_key_path"` diff --git a/app/http/middlewares/base.go b/app/http/middlewares/base.go index 929d595..e171427 100644 --- a/app/http/middlewares/base.go +++ b/app/http/middlewares/base.go @@ -109,11 +109,11 @@ func ValidateRequest() gin.HandlerFunc { func ValidatePayRequest() gin.HandlerFunc { return func(c *gin.Context) { - com, err := utils.SonicApiDataToStruct(controllers.GetRequest(c), &front.PayCommonBody{}) + commonData, err := utils.SonicApiDataToStruct(controllers.GetRequest(c), &front.RequestBody{}) if err != nil { controllers.ErrWithCode(c, errorcode.ParamError) } - comStruct := com.(*front.PayCommonBody) + commonDataStruct := commonData.(*front.RequestBody) //判断时间 //now := time.Now().UnixNano() / 1000000 //if comStruct.Timestamp > now || (config.GetConf().TimeOut != 0 && (now-comStruct.Timestamp) > config.GetConf().TimeOut) { @@ -121,7 +121,7 @@ func ValidatePayRequest() gin.HandlerFunc { // return //} //获取app信息 - app, errCode := services.AppFindOne(entities.IdRequest{Id: comStruct.AppId}) + app, errCode := services.AppFindOne(entities.IdRequest{Id: commonDataStruct.AppId}) if errCode != errorcode.Success { controllers.ErrWithCode(c, errCode) return @@ -137,7 +137,17 @@ func ValidatePayRequest() gin.HandlerFunc { controllers.ErrWithCode(c, appCheck.GetCode()) return } - + //解密 + cryptFunc := appCheck.Crypt() + if cryptFunc == nil { + controllers.ErrWithCode(c, appCheck.GetCode()) + } + data, errCode := cryptFunc(app).Decrypt(commonDataStruct.Data) + if errCode != errorcode.Success { + controllers.ErrWithCode(c, errCode) + return + } + c.Set("request", data) c.Next() } } diff --git a/app/services/api_request_valid.go b/app/services/api_request_valid.go index 16cb09e..9174112 100644 --- a/app/services/api_request_valid.go +++ b/app/services/api_request_valid.go @@ -4,6 +4,7 @@ import ( "PaymentCenter/app/constants/errorcode" "PaymentCenter/app/constants/pojo" "PaymentCenter/app/models/appmodel" + "PaymentCenter/app/services/apicrypt" "PaymentCenter/app/utils" "strings" ) @@ -35,9 +36,11 @@ func (a *AppCheck) Check() *AppCheck { if a.App.Status == pojo.STATUS_DISABLED { a.Code = errorcode.AppDisabled + return a } if a.App.DeleteTime.Location() == nil { a.Code = errorcode.AppNotFound + return a } return a } @@ -45,3 +48,14 @@ 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 +} diff --git a/app/services/apicrypt/rsa.go b/app/services/apicrypt/rsa.go index 171271d..231fd33 100644 --- a/app/services/apicrypt/rsa.go +++ b/app/services/apicrypt/rsa.go @@ -1,17 +1,38 @@ 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.MerchantPublicKey == "" { + return nil, errorcode.AppRsaEncryptKeyNotFound + } + // + encryptData, err := rsa.Encrypt(r.App.MerchantPublicKey, []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 + } + + decryptData, err := rsa.Decrypt(r.App.PrivateKey, encryptData) + if err != nil { + return nil, errorcode.AppRsaDecryptFail + } return } diff --git a/app/services/apicrypt/sm2.go b/app/services/apicrypt/sm2.go index 2a18c77..7aee726 100644 --- a/app/services/apicrypt/sm2.go +++ b/app/services/apicrypt/sm2.go @@ -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 } diff --git a/app/services/apicrypt/sm4.go b/app/services/apicrypt/sm4.go index 4e16213..9c8dcfe 100644 --- a/app/services/apicrypt/sm4.go +++ b/app/services/apicrypt/sm4.go @@ -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 + } diff --git a/app/services/apicrypt/types.go b/app/services/apicrypt/types.go index 2e6e8ec..e672fd2 100644 --- a/app/services/apicrypt/types.go +++ b/app/services/apicrypt/types.go @@ -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,9 @@ type ( App *appmodel.App } ) + +var ApiCryptMap = map[int32]func(app *appmodel.App) ApiCrypt{ + pojo.RSA: NewRsa, + pojo.SM2: NewSm2, + pojo.SM4: NewSm4, +} From 8ead5e11e28fbadea997f2e7639bf1a839182fb8 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Mon, 5 Aug 2024 10:59:02 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E5=8A=A0=E5=AF=86=E8=A7=A3=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/errorcode/error_code.go | 35 +++++++++++---------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 5102684..717a52f 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -29,30 +29,25 @@ const ( MerchantNotFound = 1100 // app -<<<<<<< HEAD + AppNotFound = 1200 AppDisabled = 1201 AppIpNotAllow = 1202 - AppRsaDecryptKeyNotFound = 1300 - AppRsaDecryptFail = 1301 - AppRsaEncryptKeyNotFound = 1302 - AppRsaEncryptFail = 1303 - AppSM2DecryptKeyNotFound = 1310 - AppSM2DecryptFail = 1311 - AppSM2EncryptKeyNotFound = 1312 - AppSM2EncryptFail = 1313 - AppSM4DecryptKeyNotFound = 1320 - AppSM4DecryptFail = 1321 - AppSM4EncryptKeyNotFound = 1322 - AppSM4EncryptFail = 1323 -======= - AppNotFound = 1200 - AppDisabled = 1201 - AppIpNotAllow = 1202 + AppRsaDecryptKeyNotFound = 1203 + AppRsaDecryptFail = 1210 + AppRsaEncryptKeyNotFound = 1211 + AppRsaEncryptFail = 1212 + AppSM2DecryptKeyNotFound = 1220 + AppSM2DecryptFail = 1221 + AppSM2EncryptKeyNotFound = 1222 + AppSM2EncryptFail = 1223 + AppSM4DecryptKeyNotFound = 1230 + AppSM4DecryptFail = 1231 + AppSM4EncryptKeyNotFound = 1232 + AppSM4EncryptFail = 1233 //渠道 PayChannelNotFound = 1300 ->>>>>>> dev/dev1.0 ) var MsgEN = map[int]string{ @@ -75,7 +70,6 @@ var MsgZH = map[int]string{ AppNotFound: "app_id未找到", AppDisabled: "app通道关闭", AppIpNotAllow: "ip不在白名单内", -<<<<<<< HEAD AppRsaDecryptKeyNotFound: "密匙缺失,无法进行Rsa解密", AppRsaDecryptFail: "Rsa解密失败", @@ -91,9 +85,8 @@ var MsgZH = map[int]string{ AppSM4DecryptFail: "sm4解密失败", AppSM4EncryptKeyNotFound: "密匙缺失,无法进行sm4加密", AppSM4EncryptFail: "sm4加密失败", -======= + PayChannelNotFound: "支付方式不存在", ->>>>>>> dev/dev1.0 } var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH} From b1a1a4cd50e84749b77c12bb7452176fb5fb98b1 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Mon, 5 Aug 2024 14:05:46 +0800 Subject: [PATCH 3/9] =?UTF-8?q?api=E8=A1=A8=E5=8D=95=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/errorcode/error_code.go | 52 ++++++++++++++------------- app/http/controllers/base.go | 28 +++++++++++++++ app/http/controllers/front/api.go | 10 ++++++ app/http/entities/front/pay.go | 6 ++-- app/http/middlewares/base.go | 33 +++++++++++++---- app/http/requestmapping/front.go | 6 ++++ app/http/routes/route.go | 12 ++++--- app/services/api_request_valid.go | 15 ++++++++ app/services/apicrypt/rsa.go | 17 +++++---- app/services/apicrypt/types.go | 2 ++ app/utils/encrypt/rsa/rsa_test.go | 7 ++-- 11 files changed, 139 insertions(+), 49 deletions(-) create mode 100644 app/http/controllers/front/api.go diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 717a52f..43a5715 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -30,21 +30,22 @@ const ( // app - AppNotFound = 1200 - AppDisabled = 1201 - AppIpNotAllow = 1202 - AppRsaDecryptKeyNotFound = 1203 - AppRsaDecryptFail = 1210 - AppRsaEncryptKeyNotFound = 1211 - AppRsaEncryptFail = 1212 - AppSM2DecryptKeyNotFound = 1220 - AppSM2DecryptFail = 1221 - AppSM2EncryptKeyNotFound = 1222 - AppSM2EncryptFail = 1223 - AppSM4DecryptKeyNotFound = 1230 - AppSM4DecryptFail = 1231 - AppSM4EncryptKeyNotFound = 1232 - AppSM4EncryptFail = 1233 + AppNotFound = 1200 + AppDisabled = 1201 + AppIpNotAllow = 1202 + AppRsaDecryptKeyNotFound = 1203 + AppDecryptDataDiscrepancy = 1204 + AppRsaDecryptFail = 1210 + AppRsaEncryptKeyNotFound = 1211 + AppRsaEncryptFail = 1212 + AppSM2DecryptKeyNotFound = 1220 + AppSM2DecryptFail = 1221 + AppSM2EncryptKeyNotFound = 1222 + AppSM2EncryptFail = 1223 + AppSM4DecryptKeyNotFound = 1230 + AppSM4DecryptFail = 1231 + AppSM4EncryptKeyNotFound = 1232 + AppSM4EncryptFail = 1233 //渠道 PayChannelNotFound = 1300 @@ -60,16 +61,17 @@ var MsgEN = map[int]string{ } var MsgZH = map[int]string{ - Success: "请求成功", - ParamError: "参数错误", - NotFound: "数据不存在", - NotAuth: "未经授权", - NotLogin: "未登录", - RequestTimeOut: "请求超时", - MerchantNotFound: "商户不存在", - AppNotFound: "app_id未找到", - AppDisabled: "app通道关闭", - AppIpNotAllow: "ip不在白名单内", + Success: "请求成功", + ParamError: "参数错误", + NotFound: "数据不存在", + NotAuth: "未经授权", + NotLogin: "未登录", + RequestTimeOut: "请求超时", + MerchantNotFound: "商户不存在", + AppNotFound: "app_id未找到", + AppDisabled: "app通道关闭", + AppIpNotAllow: "ip不在白名单内", + AppDecryptDataDiscrepancy: "解密数据不一致", AppRsaDecryptKeyNotFound: "密匙缺失,无法进行Rsa解密", AppRsaDecryptFail: "Rsa解密失败", diff --git a/app/http/controllers/base.go b/app/http/controllers/base.go index bd68940..92fd2d6 100644 --- a/app/http/controllers/base.go +++ b/app/http/controllers/base.go @@ -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) diff --git a/app/http/controllers/front/api.go b/app/http/controllers/front/api.go new file mode 100644 index 0000000..15942d1 --- /dev/null +++ b/app/http/controllers/front/api.go @@ -0,0 +1,10 @@ +package front + +import ( + "fmt" + "github.com/gin-gonic/gin" +) + +func WebPay(c *gin.Context) { + fmt.Println("312312312321") +} diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index 7efc930..67daf3b 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -1,6 +1,6 @@ package front -type PayCommonBody struct { +type ApiCommonBody struct { AppId int64 `json:"app_id" validate:"required"` Timestamp int64 `json:"timestamp" validate:"required"` } @@ -12,7 +12,7 @@ type RequestBody struct { } type PayWeb struct { - PayCommonBody - PayChannel int64 `json:"private_key_path"` + ApiCommonBody + PayChannel int64 `json:"private_key_path" validate:"required" label:"支付渠道"` Delay int64 `json:"delay"` //延时时间 } diff --git a/app/http/middlewares/base.go b/app/http/middlewares/base.go index 5958e34..c31ed96 100644 --- a/app/http/middlewares/base.go +++ b/app/http/middlewares/base.go @@ -8,6 +8,7 @@ import ( "PaymentCenter/app/http/entities/front" "PaymentCenter/app/http/requestmapping" "PaymentCenter/app/services" + "PaymentCenter/app/services/apicrypt" "PaymentCenter/app/utils" "PaymentCenter/config" "github.com/gin-gonic/gin" @@ -107,7 +108,7 @@ func ValidateRequest() gin.HandlerFunc { if strings.Index(path, "admin") >= 0 { handler = requestmapping.BackendRequestMap[path] } else { - handler = requestmapping.FrontRequestMap[path] + handler = requestmapping.FrontRequest() } if handler == nil { utils.Log(c, "path", path) @@ -129,11 +130,14 @@ func ValidateRequest() gin.HandlerFunc { func ValidatePayRequest() gin.HandlerFunc { return func(c *gin.Context) { - commonData, err := utils.SonicApiDataToStruct(controllers.GetRequest(c), &front.RequestBody{}) + 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) + return } - commonDataStruct := commonData.(*front.RequestBody) + requestDataStruct := requestData.(*front.RequestBody) //判断时间 //now := time.Now().UnixNano() / 1000000 //if comStruct.Timestamp > now || (config.GetConf().TimeOut != 0 && (now-comStruct.Timestamp) > config.GetConf().TimeOut) { @@ -141,7 +145,7 @@ func ValidatePayRequest() gin.HandlerFunc { // return //} //获取app信息 - app, errCode := services.AppFindOne(entities.IdRequest{Id: commonDataStruct.AppId}) + app, errCode := services.AppFindOne(entities.IdRequest{Id: requestDataStruct.AppId}) if errCode != errorcode.Success { controllers.ErrWithCode(c, errCode) return @@ -162,12 +166,27 @@ func ValidatePayRequest() gin.HandlerFunc { if cryptFunc == nil { controllers.ErrWithCode(c, appCheck.GetCode()) } - data, errCode := cryptFunc(app).Decrypt(commonDataStruct.Data) - if errCode != errorcode.Success { + dataByte, errCode := cryptFunc(app).Decrypt(requestDataStruct.Data) + if errCode != apicrypt.CryptNotError { controllers.ErrWithCode(c, errCode) return } - c.Set("request", data) + //检查解密后的数据是否与请求一致 + reCheck := appCheck.ReCheckAfterDecrypt(dataByte, requestDataStruct) + if !reCheck { + controllers.ErrWithCode(c, 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.Error(c, errorcode.ParamError, msg...) + c.Abort() + } + c.Set("request", dataByte) c.Next() } } diff --git a/app/http/requestmapping/front.go b/app/http/requestmapping/front.go index 5660770..9aa8e13 100644 --- a/app/http/requestmapping/front.go +++ b/app/http/requestmapping/front.go @@ -8,3 +8,9 @@ import ( var FrontRequestMap = map[string]func() interface{}{ common.FRONT_V1 + "/pay/web": func() interface{} { return new(front.PayWeb) }, } + +func FrontRequest() func() interface{} { + return func() interface{} { + return new(front.RequestBody) + } +} diff --git a/app/http/routes/route.go b/app/http/routes/route.go index e0dc7ff..c1df4fa 100644 --- a/app/http/routes/route.go +++ b/app/http/routes/route.go @@ -4,8 +4,8 @@ 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" @@ -47,7 +47,7 @@ func RegisterRoute(router *gin.Engine) { //router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - v1 := router.Group("/v1") + v1 := router.Group(common.FRONT_V1) { //回调处理 notify := v1.Group("/notify") @@ -55,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("/web", front.WebPay) + } } router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - pay := v1.Group("pay", middlewares.ValidatePayRequest()) - pay.POST("web", backend.MerchantList) // 商户列表 + } diff --git a/app/services/api_request_valid.go b/app/services/api_request_valid.go index 9174112..0c6ed47 100644 --- a/app/services/api_request_valid.go +++ b/app/services/api_request_valid.go @@ -3,9 +3,11 @@ package services import ( "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" ) @@ -59,3 +61,16 @@ func (a *AppCheck) Crypt() (cryptFunc func(app *appmodel.App) apicrypt.ApiCrypt) } 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 +} diff --git a/app/services/apicrypt/rsa.go b/app/services/apicrypt/rsa.go index 231fd33..69012ac 100644 --- a/app/services/apicrypt/rsa.go +++ b/app/services/apicrypt/rsa.go @@ -13,11 +13,13 @@ func NewRsa(app *appmodel.App) ApiCrypt { } func (r *Rsa) Encrypt(decryptData string) (encryptData []byte, errCode int) { - if r.App.MerchantPublicKey == "" { + if r.App.PublicKey == "" { return nil, errorcode.AppRsaEncryptKeyNotFound } - // - encryptData, err := rsa.Encrypt(r.App.MerchantPublicKey, []byte(decryptData)) + publicKeyPEM := `-----BEGIN PUBLIC KEY----- +` + r.App.PublicKey + ` +-----END PUBLIC KEY-----` + encryptData, err := rsa.Encrypt(publicKeyPEM, []byte(decryptData)) if err != nil { return nil, errorcode.AppRsaEncryptFail } @@ -26,12 +28,15 @@ func (r *Rsa) Encrypt(decryptData string) (encryptData []byte, errCode int) { } func (r *Rsa) Decrypt(encryptData string) (decryptData []byte, errCode int) { + if r.App.PrivateKey == "" { return nil, errorcode.AppRsaDecryptKeyNotFound } - - decryptData, err := rsa.Decrypt(r.App.PrivateKey, encryptData) - if err != nil { + 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 diff --git a/app/services/apicrypt/types.go b/app/services/apicrypt/types.go index e672fd2..533de39 100644 --- a/app/services/apicrypt/types.go +++ b/app/services/apicrypt/types.go @@ -29,3 +29,5 @@ var ApiCryptMap = map[int32]func(app *appmodel.App) ApiCrypt{ pojo.SM2: NewSm2, pojo.SM4: NewSm4, } + +const CryptNotError = 0 diff --git a/app/utils/encrypt/rsa/rsa_test.go b/app/utils/encrypt/rsa/rsa_test.go index 5425c75..628568e 100644 --- a/app/utils/encrypt/rsa/rsa_test.go +++ b/app/utils/encrypt/rsa/rsa_test.go @@ -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 := "{\"app_id\":5476377146882523138,\"name\":\"张三\",\"sex\":1,\"is_human\":true,\"timestamp\":53612533412643}" dataJson := []byte(data) pub := `-----BEGIN PUBLIC KEY----- ` + PUB + ` From 3e7df62375b55356422e5933fecc984a3412ac96 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Mon, 5 Aug 2024 16:20:01 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=E7=BD=91=E9=A1=B5=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/data/app.go | 1 - app/data/merchat.go | 9 +++++++ app/http/controllers/base.go | 8 ++++++ app/http/controllers/front/api.go | 9 +++++-- app/http/entities/front/pay.go | 9 ++++--- app/http/middlewares/base.go | 25 +++++++------------ app/http/requestmapping/front.go | 2 +- app/services/api_request_valid.go | 6 +++-- app/services/app.go | 22 ++++++++++++++++- app/services/merchant.go | 26 ++++++++++++++++++++ app/services/web_pay.go | 41 +++++++++++++++++++++++++++++++ 11 files changed, 132 insertions(+), 26 deletions(-) create mode 100644 app/services/web_pay.go diff --git a/app/data/app.go b/app/data/app.go index f355d0f..475d0ce 100644 --- a/app/data/app.go +++ b/app/data/app.go @@ -45,5 +45,4 @@ func (m *AppRepo) AppFindOne(app *appmodel.App, conn builder.Cond, columns ...st return nil, sql.ErrNoRows } return app, err - } diff --git a/app/data/merchat.go b/app/data/merchat.go index 763758c..3b85a0b 100644 --- a/app/data/merchat.go +++ b/app/data/merchat.go @@ -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 +} diff --git a/app/http/controllers/base.go b/app/http/controllers/base.go index 92fd2d6..03afeee 100644 --- a/app/http/controllers/base.go +++ b/app/http/controllers/base.go @@ -192,6 +192,14 @@ 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 HandRes(c *gin.Context, data interface{}, err error) { if err == nil { Success(c, data, "") diff --git a/app/http/controllers/front/api.go b/app/http/controllers/front/api.go index 15942d1..48f709d 100644 --- a/app/http/controllers/front/api.go +++ b/app/http/controllers/front/api.go @@ -1,10 +1,15 @@ package front import ( - "fmt" + "PaymentCenter/app/http/controllers" + "PaymentCenter/app/http/entities/front" + "PaymentCenter/app/services" "github.com/gin-gonic/gin" ) func WebPay(c *gin.Context) { - fmt.Println("312312312321") + req := controllers.GetRequest(c).(*front.PayWebReqs) + appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck) + services.NewWebPay(req, appCheckInfo) + } diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index 67daf3b..bf63994 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -11,8 +11,11 @@ type RequestBody struct { Data string `json:"data" validate:"required"` } -type PayWeb struct { +type PayWebReqs struct { ApiCommonBody - PayChannel int64 `json:"private_key_path" validate:"required" label:"支付渠道"` - Delay int64 `json:"delay"` //延时时间 + PayChannelId int64 `json:"pay_channel_id" validate:"required" label:"支付渠道"` + OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"` + OrderType int32 `json:"order_type" validate:"required" label:"订单类型,支付,退款"` + Amount int64 `json:"amount" validate:"required" label:"支付金额,单位分"` + ExtJson string `json:"ext_json" validate:"required" label:"扩展参数"` } diff --git a/app/http/middlewares/base.go b/app/http/middlewares/base.go index c31ed96..220a59a 100644 --- a/app/http/middlewares/base.go +++ b/app/http/middlewares/base.go @@ -4,7 +4,6 @@ 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" @@ -145,20 +144,13 @@ func ValidatePayRequest() gin.HandlerFunc { // return //} //获取app信息 - app, errCode := services.AppFindOne(entities.IdRequest{Id: requestDataStruct.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()) + appCheck := services.AppGetAndCheck(&services.AppCheck{ + AppId: requestDataStruct.AppId, + Ip: c.ClientIP(), + Code: errorcode.Success, + }) + if appCheck.Code != errorcode.Success { + controllers.ErrWithCode(c, appCheck.Code) return } //解密 @@ -166,7 +158,7 @@ func ValidatePayRequest() gin.HandlerFunc { if cryptFunc == nil { controllers.ErrWithCode(c, appCheck.GetCode()) } - dataByte, errCode := cryptFunc(app).Decrypt(requestDataStruct.Data) + dataByte, errCode := cryptFunc(appCheck.App).Decrypt(requestDataStruct.Data) if errCode != apicrypt.CryptNotError { controllers.ErrWithCode(c, errCode) return @@ -187,6 +179,7 @@ func ValidatePayRequest() gin.HandlerFunc { c.Abort() } c.Set("request", dataByte) + c.Set("appCheckInfo", appCheck) c.Next() } } diff --git a/app/http/requestmapping/front.go b/app/http/requestmapping/front.go index 9aa8e13..79e6f2c 100644 --- a/app/http/requestmapping/front.go +++ b/app/http/requestmapping/front.go @@ -6,7 +6,7 @@ import ( ) var FrontRequestMap = map[string]func() interface{}{ - common.FRONT_V1 + "/pay/web": func() interface{} { return new(front.PayWeb) }, + common.FRONT_V1 + "/pay/web": func() interface{} { return new(front.PayWebResp) }, } func FrontRequest() func() interface{} { diff --git a/app/services/api_request_valid.go b/app/services/api_request_valid.go index 0c6ed47..4a8a251 100644 --- a/app/services/api_request_valid.go +++ b/app/services/api_request_valid.go @@ -12,8 +12,10 @@ import ( ) type AppCheck struct { - App *appmodel.App - Code int + AppId int64 + Ip string + App *appmodel.App + Code int } func NewAppCheck(app *appmodel.App) *AppCheck { diff --git a/app/services/app.go b/app/services/app.go index a161494..88ce3d3 100644 --- a/app/services/app.go +++ b/app/services/app.go @@ -65,7 +65,7 @@ func AppUpdate(app *appmodel.App) (code int) { } else { _, err = repo.AppUpdate(app, conn) } - + code = handErr(err) return } @@ -99,3 +99,23 @@ func AppFindOne(req entities.IdRequest, col ...string) (row *appmodel.App, code } return row, errorcode.Success } + +func AppGetAndCheck(appCheckIn *AppCheck) (appCheckOut *AppCheck) { + errCode := errorcode.Success + appCheckOut.App, errCode = AppFindOne(entities.IdRequest{Id: appCheckIn.AppId}) + if errCode != errorcode.Success { + appCheckOut.Code = errCode + return + } + //检查app可用性 + appCheckOut = appCheckIn.Check() + if appCheckOut.GetCode() != errorcode.Success { + return + } + //检查白名单 + if appCheckIn.Ip != "" && !appCheckOut.IpCheck(appCheckIn.Ip) { + return + } + + return +} diff --git a/app/services/merchant.go b/app/services/merchant.go index 99d80f1..d8f98c3 100644 --- a/app/services/merchant.go +++ b/app/services/merchant.go @@ -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,27 @@ 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) (code int) { + merchantInfo, code := MerchantFindOne(merchant, conn, col...) + if code != errorcode.Success { + return code + } + if merchantInfo.DeleteTime.Location() != nil { + return errorcode.MerchantNotFound + } + return +} diff --git a/app/services/web_pay.go b/app/services/web_pay.go new file mode 100644 index 0000000..ab1c9d7 --- /dev/null +++ b/app/services/web_pay.go @@ -0,0 +1,41 @@ +package services + +import ( + "PaymentCenter/app/constants/errorcode" + "PaymentCenter/app/data" + "PaymentCenter/app/http/entities/front" + "PaymentCenter/app/models/merchantmodel" +) + +type WebPay struct { + WebPayReqs *front.PayWebReqs + AppCheck *AppCheck + Order *data.OrderRepo + PayCode int +} + +func NewWebPay(resp *front.PayWebReqs, appCheck *AppCheck) *WebPay { + if appCheck == nil { + appCheck = AppGetAndCheck(&AppCheck{ + AppId: resp.AppId, + Code: errorcode.Success, + }) + } + return &WebPay{ + WebPayReqs: resp, + AppCheck: appCheck, + PayCode: appCheck.Code, + } +} + +func (w *WebPay) AddPayLog() { + w.PayCode = GetAndCheckMerchant(&merchantmodel.Merchant{Id: w.AppCheck.App.MerchantId}, nil) +} + +func (w *WebPay) CheckMerchant() { + w.PayCode = GetAndCheckMerchant(&merchantmodel.Merchant{Id: w.AppCheck.App.MerchantId}, nil) +} + +func (w *WebPay) CheckPayChannel() { + w.PayCode = GetAndCheckMerchant(&merchantmodel.Merchant{Id: w.AppCheck.App.MerchantId}, nil) +} From 79723bd9455d8e2a3d641dd9995870af481705e1 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Mon, 5 Aug 2024 17:07:11 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=87=86=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/errorcode/error_code.go | 8 ++++++++ app/data/orders.go | 9 +++++++++ app/data/pay_channel.go | 9 +++++++++ app/services/order.go | 26 ++++++++++++++++++++++++++ app/services/pay_channel.go | 25 +++++++++++++++++++++++++ app/services/request_log.go | 14 ++++++++++++++ app/services/web_pay.go | 25 +++++++++++++++++++++++-- 7 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 app/services/request_log.go diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 43a5715..06a5b5a 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -49,6 +49,12 @@ const ( //渠道 PayChannelNotFound = 1300 + + //订单 + OrdersNotFound = 1300 + + //网页支付 + RequestLogErrors = 1400 ) var MsgEN = map[int]string{ @@ -89,6 +95,8 @@ var MsgZH = map[int]string{ AppSM4EncryptFail: "sm4加密失败", PayChannelNotFound: "支付方式不存在", + + RequestLogErrors: "请求日志错误", } var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH} diff --git a/app/data/orders.go b/app/data/orders.go index 9bc6c7e..eda2d8d 100644 --- a/app/data/orders.go +++ b/app/data/orders.go @@ -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_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 +} diff --git a/app/data/pay_channel.go b/app/data/pay_channel.go index 8647765..b6438c8 100644 --- a/app/data/pay_channel.go +++ b/app/data/pay_channel.go @@ -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 +} diff --git a/app/services/order.go b/app/services/order.go index c653105..c02d463 100644 --- a/app/services/order.go +++ b/app/services/order.go @@ -1,12 +1,15 @@ package services import ( + "PaymentCenter/app/constants/common" + "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 +75,26 @@ func OrderLogsList(req backend.OrderLogsListRequest) (requestLog []orderrequestl return orderLogList, thirdLogList, code } + +func OrderFindOne(order *ordersmodel.Orders, conn builder.Cond, col ...string) (merchantInfo *ordersmodel.Orders, code int) { + repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb()) + // 拼接查询条件 + orderInfo, err := repo.OrderFindOne(order, conn, col...) + if err != nil { + if err == sql.ErrNoRows { + return nil, errorcode.OrdersNotFound + } + return nil, errorcode.SystemError + } + return orderInfo, errorcode.Success +} + +func HadSameValueOrder(order *ordersmodel.Orders) (exist bool, code int) { + conn := builder.NewCond() + conn = conn.And(builder.Neq{"Status": common.ORDER_STATUS_CLOSE}) + _, code = OrderFindOne(order, conn) + if code != errorcode.OrdersNotFound { + return false, errorcode.Success + } + return true, code +} diff --git a/app/services/pay_channel.go b/app/services/pay_channel.go index 6cfe4f6..7d0a4c8 100644 --- a/app/services/pay_channel.go +++ b/app/services/pay_channel.go @@ -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) (code int) { + merchantInfo, code := PayChannelFindOne(channel, conn, col...) + if code != errorcode.Success { + return code + } + if merchantInfo.DeleteTime.Location() != nil { + return errorcode.PayChannelNotFound + } + return +} diff --git a/app/services/request_log.go b/app/services/request_log.go new file mode 100644 index 0000000..8f3f122 --- /dev/null +++ b/app/services/request_log.go @@ -0,0 +1,14 @@ +package services + +import ( + "PaymentCenter/app/data" + "PaymentCenter/app/models/orderrequestlogmodel" +) + +func RequestLogCreate(log *orderrequestlogmodel.OrderRequestLog) (code int) { + db := orderrequestlogmodel.GetInstance().GetDb() + repo := data.NewOrderRequestLogRepo(db) + _, err := repo.OrderRequestLogInsertOne(log) + code = handErr(err) + return +} diff --git a/app/services/web_pay.go b/app/services/web_pay.go index ab1c9d7..6fe8660 100644 --- a/app/services/web_pay.go +++ b/app/services/web_pay.go @@ -5,6 +5,10 @@ import ( "PaymentCenter/app/data" "PaymentCenter/app/http/entities/front" "PaymentCenter/app/models/merchantmodel" + "PaymentCenter/app/models/orderrequestlogmodel" + "PaymentCenter/app/models/ordersmodel" + "PaymentCenter/app/models/paychannelmodel" + "github.com/bytedance/sonic" ) type WebPay struct { @@ -29,13 +33,30 @@ func NewWebPay(resp *front.PayWebReqs, appCheck *AppCheck) *WebPay { } func (w *WebPay) AddPayLog() { - w.PayCode = GetAndCheckMerchant(&merchantmodel.Merchant{Id: w.AppCheck.App.MerchantId}, nil) + requestJson, err := sonic.Marshal(w.WebPayReqs) + if err != nil { + w.PayCode = errorcode.RequestLogErrors + return + } + code := RequestLogCreate(&orderrequestlogmodel.OrderRequestLog{ + IpAddress: w.AppCheck.Ip, + MerchantRequest: string(requestJson), + }) + w.PayCode = code + return } func (w *WebPay) CheckMerchant() { - w.PayCode = GetAndCheckMerchant(&merchantmodel.Merchant{Id: w.AppCheck.App.MerchantId}, nil) + w.PayCode = GetAndCheckPayChannel(&paychannelmodel.PayChannel{Id: w.WebPayReqs.PayChannelId}, nil) } func (w *WebPay) CheckPayChannel() { w.PayCode = GetAndCheckMerchant(&merchantmodel.Merchant{Id: w.AppCheck.App.MerchantId}, nil) } + +func (w *WebPay) CheckOrder() { + exist, code := HadSameValueOrder(&ordersmodel.Orders{OutTreadNo: w.WebPayReqs.OutTradeNo}) + if exist { + w.PayCode = code + } +} From 548491c1f155619895bde713d2fbee1b0cc2ca85 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Mon, 5 Aug 2024 18:45:01 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E6=94=AF=E4=BB=98=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/common/common.go | 22 +++++ app/constants/errorcode/error_code.go | 19 ++-- app/constants/pojo/common.go | 6 -- app/http/controllers/front/api.go | 5 +- app/http/entities/front/pay.go | 5 +- app/models/ordersmodel/orders.go | 3 +- app/services/api_request_valid.go | 4 +- app/services/merchant.go | 8 +- app/services/order.go | 10 ++- app/services/pay.go | 45 ++++++++++ app/services/pay_channel.go | 8 +- app/services/thirdpay/web_pay.go | 123 ++++++++++++++++++++++++++ app/services/web_pay.go | 62 ------------- 13 files changed, 231 insertions(+), 89 deletions(-) delete mode 100644 app/constants/pojo/common.go create mode 100644 app/services/pay.go create mode 100644 app/services/thirdpay/web_pay.go delete mode 100644 app/services/web_pay.go diff --git a/app/constants/common/common.go b/app/constants/common/common.go index 6439c26..02190fd 100644 --- a/app/constants/common/common.go +++ b/app/constants/common/common.go @@ -28,4 +28,26 @@ const ( ORDER_STATUS_PAYED = 3 ORDER_STATUS_FAILED = 4 ORDER_STATUS_CLOSE = 5 + + STATUS_ENABLE int32 = 1 + STATUS_DISABLED int32 = 2 + + ORDER_TYPE_PAY int32 = 1 + ORDER_TYPE_REFUND int32 = 2 ) + +var PayChannelList = map[int]string{ + PAY_CHANNEL_WECHAT_JSAPI: "微信JSAPI", + PAY_CHANNEL_WECHAT_H5: "微信H5", + PAY_CHANNEL_WECHAT_APP: "微信app", + PAY_CHANNEL_WECHAT_NATIVE: "微信Native", + PAY_CHANNEL_WECHAT_MINI: "微信小程序", + PAY_CHANNEL_ALIPAY_WEB: "支付宝网页&移动应用", + PAY_CHANNEL_ALIPAY_MINI: "支付宝小程序", + PAY_CHANNEL_ALIPAY_JSAPI: "支付宝JSAPI", +} + +var OrderTypeList = map[int32]string{ + ORDER_TYPE_PAY: "付款", + ORDER_TYPE_REFUND: "退款", +} diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 06a5b5a..5b248fd 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -48,13 +48,16 @@ const ( AppSM4EncryptFail = 1233 //渠道 - PayChannelNotFound = 1300 + PayChannelNotFound = 1300 + PayChannelNotBuild = 1301 + PayChannelExtJsonError = 1302 //订单 - OrdersNotFound = 1300 - + OrdersNotFound = 1401 + OrdersExist = 1402 + OrderTypeNotFount = 1403 //网页支付 - RequestLogErrors = 1400 + RequestLogErrors = 1500 ) var MsgEN = map[int]string{ @@ -94,9 +97,15 @@ var MsgZH = map[int]string{ AppSM4EncryptKeyNotFound: "密匙缺失,无法进行sm4加密", AppSM4EncryptFail: "sm4加密失败", - PayChannelNotFound: "支付方式不存在", + PayChannelNotFound: "支付方式不存在", + PayChannelNotBuild: "支付方式尚未开通", + PayChannelExtJsonError: "支付方式扩展参数错误", RequestLogErrors: "请求日志错误", + + OrdersNotFound: "未找到订单", + OrdersExist: "订单已存在", + OrderTypeNotFount: "未知的支付方式", } var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH} diff --git a/app/constants/pojo/common.go b/app/constants/pojo/common.go deleted file mode 100644 index 1e58d13..0000000 --- a/app/constants/pojo/common.go +++ /dev/null @@ -1,6 +0,0 @@ -package pojo - -const ( - STATUS_ENABLE int32 = 1 - STATUS_DISABLED int32 = 2 -) diff --git a/app/http/controllers/front/api.go b/app/http/controllers/front/api.go index 48f709d..b23b617 100644 --- a/app/http/controllers/front/api.go +++ b/app/http/controllers/front/api.go @@ -10,6 +10,7 @@ import ( func WebPay(c *gin.Context) { req := controllers.GetRequest(c).(*front.PayWebReqs) appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck) - services.NewWebPay(req, appCheckInfo) - + code := services.ThirdPayWeb(c.Request.Context(), req, appCheckInfo, c.ClientIP()) + controllers.ErrWithCode(c, code) + return } diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index bf63994..56bbcb7 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -16,6 +16,7 @@ type PayWebReqs struct { PayChannelId int64 `json:"pay_channel_id" validate:"required" label:"支付渠道"` OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"` OrderType int32 `json:"order_type" validate:"required" label:"订单类型,支付,退款"` - Amount int64 `json:"amount" validate:"required" label:"支付金额,单位分"` - ExtJson string `json:"ext_json" validate:"required" label:"扩展参数"` + Amount int `json:"amount" validate:"required" label:"支付金额,单位分"` + ExtJson string `json:"ext_json" label:"扩展参数"` + Desc string `json:"desc" validate:"max=100" label:"商品描述"` } diff --git a/app/models/ordersmodel/orders.go b/app/models/ordersmodel/orders.go index 798bddf..f6dd2f2 100644 --- a/app/models/ordersmodel/orders.go +++ b/app/models/ordersmodel/orders.go @@ -18,9 +18,10 @@ type Orders struct { 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"` + OrderType int32 `xorm:"'order_type' TINYINT"` Amount int `xorm:"'amount' 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"` diff --git a/app/services/api_request_valid.go b/app/services/api_request_valid.go index 4a8a251..ccdbbb8 100644 --- a/app/services/api_request_valid.go +++ b/app/services/api_request_valid.go @@ -1,8 +1,8 @@ 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" @@ -38,7 +38,7 @@ 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 } diff --git a/app/services/merchant.go b/app/services/merchant.go index d8f98c3..386d965 100644 --- a/app/services/merchant.go +++ b/app/services/merchant.go @@ -81,13 +81,13 @@ func MerchantFindOne(merchant *merchantmodel.Merchant, conn builder.Cond, col .. return merchantInfo, errorcode.Success } -func GetAndCheckMerchant(merchant *merchantmodel.Merchant, conn builder.Cond, col ...string) (code int) { - merchantInfo, code := MerchantFindOne(merchant, conn, col...) +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 code + return nil, code } if merchantInfo.DeleteTime.Location() != nil { - return errorcode.MerchantNotFound + return nil, errorcode.MerchantNotFound } return } diff --git a/app/services/order.go b/app/services/order.go index c02d463..76fdc91 100644 --- a/app/services/order.go +++ b/app/services/order.go @@ -76,6 +76,14 @@ 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()) + orderId, err := repo.OrderInsertOne(orderIn) + orderIn.Id = orderId + code = handErr(err) + return orderIn, code +} + func OrderFindOne(order *ordersmodel.Orders, conn builder.Cond, col ...string) (merchantInfo *ordersmodel.Orders, code int) { repo := data.NewOrderRepo(ordersmodel.GetInstance().GetDb()) // 拼接查询条件 @@ -86,7 +94,7 @@ func OrderFindOne(order *ordersmodel.Orders, conn builder.Cond, col ...string) ( } return nil, errorcode.SystemError } - return orderInfo, errorcode.Success + return orderInfo, errorcode.OrdersExist } func HadSameValueOrder(order *ordersmodel.Orders) (exist bool, code int) { diff --git a/app/services/pay.go b/app/services/pay.go new file mode 100644 index 0000000..79b1a6d --- /dev/null +++ b/app/services/pay.go @@ -0,0 +1,45 @@ +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 +} diff --git a/app/services/pay_channel.go b/app/services/pay_channel.go index 7d0a4c8..26d47bd 100644 --- a/app/services/pay_channel.go +++ b/app/services/pay_channel.go @@ -107,13 +107,13 @@ func PayChannelFindOne(channel *paychannelmodel.PayChannel, conn builder.Cond, c return channelInfo, errorcode.Success } -func GetAndCheckPayChannel(channel *paychannelmodel.PayChannel, conn builder.Cond, col ...string) (code int) { - merchantInfo, code := PayChannelFindOne(channel, conn, col...) +func GetAndCheckPayChannel(channel *paychannelmodel.PayChannel, conn builder.Cond, col ...string) (merchantInfo *paychannelmodel.PayChannel, code int) { + merchantInfo, code = PayChannelFindOne(channel, conn, col...) if code != errorcode.Success { - return code + return nil, code } if merchantInfo.DeleteTime.Location() != nil { - return errorcode.PayChannelNotFound + return nil, errorcode.PayChannelNotFound } return } diff --git a/app/services/thirdpay/web_pay.go b/app/services/thirdpay/web_pay.go new file mode 100644 index 0000000..406e060 --- /dev/null +++ b/app/services/thirdpay/web_pay.go @@ -0,0 +1,123 @@ +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 +} diff --git a/app/services/web_pay.go b/app/services/web_pay.go deleted file mode 100644 index 6fe8660..0000000 --- a/app/services/web_pay.go +++ /dev/null @@ -1,62 +0,0 @@ -package services - -import ( - "PaymentCenter/app/constants/errorcode" - "PaymentCenter/app/data" - "PaymentCenter/app/http/entities/front" - "PaymentCenter/app/models/merchantmodel" - "PaymentCenter/app/models/orderrequestlogmodel" - "PaymentCenter/app/models/ordersmodel" - "PaymentCenter/app/models/paychannelmodel" - "github.com/bytedance/sonic" -) - -type WebPay struct { - WebPayReqs *front.PayWebReqs - AppCheck *AppCheck - Order *data.OrderRepo - PayCode int -} - -func NewWebPay(resp *front.PayWebReqs, appCheck *AppCheck) *WebPay { - if appCheck == nil { - appCheck = AppGetAndCheck(&AppCheck{ - AppId: resp.AppId, - Code: errorcode.Success, - }) - } - return &WebPay{ - WebPayReqs: resp, - AppCheck: appCheck, - PayCode: appCheck.Code, - } -} - -func (w *WebPay) AddPayLog() { - requestJson, err := sonic.Marshal(w.WebPayReqs) - if err != nil { - w.PayCode = errorcode.RequestLogErrors - return - } - code := RequestLogCreate(&orderrequestlogmodel.OrderRequestLog{ - IpAddress: w.AppCheck.Ip, - MerchantRequest: string(requestJson), - }) - w.PayCode = code - return -} - -func (w *WebPay) CheckMerchant() { - w.PayCode = GetAndCheckPayChannel(&paychannelmodel.PayChannel{Id: w.WebPayReqs.PayChannelId}, nil) -} - -func (w *WebPay) CheckPayChannel() { - w.PayCode = GetAndCheckMerchant(&merchantmodel.Merchant{Id: w.AppCheck.App.MerchantId}, nil) -} - -func (w *WebPay) CheckOrder() { - exist, code := HadSameValueOrder(&ordersmodel.Orders{OutTreadNo: w.WebPayReqs.OutTradeNo}) - if exist { - w.PayCode = code - } -} From 943c3401c66913c63f92a57fb38610269745347c Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Tue, 6 Aug 2024 16:53:59 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E6=94=AF=E4=BB=98=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/console/command.go | 2 +- app/constants/errorcode/error_code.go | 11 +- app/http/controllers/api.go | 102 +++++++++++++++ app/http/controllers/base.go | 5 + app/http/controllers/front/api.go | 24 +++- app/http/entities/backend/order.go | 16 ++- app/http/entities/front/pay.go | 8 +- app/http/middlewares/base.go | 42 +++--- app/http/requestmapping/front.go | 8 +- app/http/routes/route.go | 2 +- .../orderrequestlogmodel/order_request_log.go | 4 +- app/models/ordersmodel/orders.go | 2 +- app/models/paychannelmodel/pay_channel.go | 2 +- app/services/api_request_valid.go | 2 +- app/services/app.go | 23 +++- app/services/merchant.go | 3 +- app/services/order.go | 8 +- app/services/pay.go | 45 ------- app/services/pay_channel.go | 6 +- app/services/request_log.go | 37 +++++- app/services/thirdpay/do/pay.go | 64 +++++++++ app/services/thirdpay/do/pay_check.go | 69 ++++++++++ app/services/thirdpay/do/pay_way.go | 28 ++++ app/services/thirdpay/pay.go | 62 +++++++++ app/services/thirdpay/types/callback.go | 10 ++ app/services/thirdpay/web_pay.go | 123 ------------------ app/third/paymentService/payment_service.go | 8 ++ app/utils/encrypt/rsa/rsa_test.go | 2 +- 28 files changed, 486 insertions(+), 232 deletions(-) create mode 100644 app/http/controllers/api.go delete mode 100644 app/services/pay.go create mode 100644 app/services/thirdpay/do/pay.go create mode 100644 app/services/thirdpay/do/pay_check.go create mode 100644 app/services/thirdpay/do/pay_way.go create mode 100644 app/services/thirdpay/pay.go create mode 100644 app/services/thirdpay/types/callback.go delete mode 100644 app/services/thirdpay/web_pay.go diff --git a/app/console/command.go b/app/console/command.go index fb8e8de..dd7a3e2 100644 --- a/app/console/command.go +++ b/app/console/command.go @@ -125,7 +125,7 @@ func queryOrder() { // 更新订单状态 todo orderUpdate := ordersmodel.Orders{ Id: orderInfo.Id, - Status: status, + Status: int32(status), } session := ordersmodel.GetInstance().GetDb().NewSession() diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 5b248fd..d7b4235 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -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: "订单已存在", diff --git a/app/http/controllers/api.go b/app/http/controllers/api.go new file mode 100644 index 0000000..ec1e2eb --- /dev/null +++ b/app/http/controllers/api.go @@ -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() +} diff --git a/app/http/controllers/base.go b/app/http/controllers/base.go index 03afeee..b42fd4d 100644 --- a/app/http/controllers/base.go +++ b/app/http/controllers/base.go @@ -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, "") diff --git a/app/http/controllers/front/api.go b/app/http/controllers/front/api.go index b23b617..fd7f2da 100644 --- a/app/http/controllers/front/api.go +++ b/app/http/controllers/front/api.go @@ -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 } diff --git a/app/http/entities/backend/order.go b/app/http/entities/backend/order.go index 8ff87bd..6e14a6f 100644 --- a/app/http/entities/backend/order.go +++ b/app/http/entities/backend/order.go @@ -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"` diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index 56bbcb7..150f3ff 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -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{} +} diff --git a/app/http/middlewares/base.go b/app/http/middlewares/base.go index 220a59a..0bdf33e 100644 --- a/app/http/middlewares/base.go +++ b/app/http/middlewares/base.go @@ -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() } diff --git a/app/http/requestmapping/front.go b/app/http/requestmapping/front.go index 79e6f2c..bf8173d 100644 --- a/app/http/requestmapping/front.go +++ b/app/http/requestmapping/front.go @@ -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) }, } diff --git a/app/http/routes/route.go b/app/http/routes/route.go index c1df4fa..65deec4 100644 --- a/app/http/routes/route.go +++ b/app/http/routes/route.go @@ -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) } } diff --git a/app/models/orderrequestlogmodel/order_request_log.go b/app/models/orderrequestlogmodel/order_request_log.go index 961b6e6..892fa44 100644 --- a/app/models/orderrequestlogmodel/order_request_log.go +++ b/app/models/orderrequestlogmodel/order_request_log.go @@ -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"` } // 表名 diff --git a/app/models/ordersmodel/orders.go b/app/models/ordersmodel/orders.go index f6dd2f2..ba3999a 100644 --- a/app/models/ordersmodel/orders.go +++ b/app/models/ordersmodel/orders.go @@ -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"` } diff --git a/app/models/paychannelmodel/pay_channel.go b/app/models/paychannelmodel/pay_channel.go index 7b65f10..c99448b 100644 --- a/app/models/paychannelmodel/pay_channel.go +++ b/app/models/paychannelmodel/pay_channel.go @@ -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"` diff --git a/app/services/api_request_valid.go b/app/services/api_request_valid.go index ccdbbb8..ca007ce 100644 --- a/app/services/api_request_valid.go +++ b/app/services/api_request_valid.go @@ -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 } diff --git a/app/services/app.go b/app/services/app.go index 88ce3d3..371ecce 100644 --- a/app/services/app.go +++ b/app/services/app.go @@ -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 +} diff --git a/app/services/merchant.go b/app/services/merchant.go index 386d965..abba737 100644 --- a/app/services/merchant.go +++ b/app/services/merchant.go @@ -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 diff --git a/app/services/order.go b/app/services/order.go index 76fdc91..7e62603 100644 --- a/app/services/order.go +++ b/app/services/order.go @@ -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 diff --git a/app/services/pay.go b/app/services/pay.go deleted file mode 100644 index 79b1a6d..0000000 --- a/app/services/pay.go +++ /dev/null @@ -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 -} diff --git a/app/services/pay_channel.go b/app/services/pay_channel.go index 26d47bd..fd88eb6 100644 --- a/app/services/pay_channel.go +++ b/app/services/pay_channel.go @@ -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 diff --git a/app/services/request_log.go b/app/services/request_log.go index 8f3f122..f84bdda 100644 --- a/app/services/request_log.go +++ b/app/services/request_log.go @@ -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 } diff --git a/app/services/thirdpay/do/pay.go b/app/services/thirdpay/do/pay.go new file mode 100644 index 0000000..184a946 --- /dev/null +++ b/app/services/thirdpay/do/pay.go @@ -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 +} diff --git a/app/services/thirdpay/do/pay_check.go b/app/services/thirdpay/do/pay_check.go new file mode 100644 index 0000000..e3228e4 --- /dev/null +++ b/app/services/thirdpay/do/pay_check.go @@ -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 +} diff --git a/app/services/thirdpay/do/pay_way.go b/app/services/thirdpay/do/pay_way.go new file mode 100644 index 0000000..b367964 --- /dev/null +++ b/app/services/thirdpay/do/pay_way.go @@ -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 +} diff --git a/app/services/thirdpay/pay.go b/app/services/thirdpay/pay.go new file mode 100644 index 0000000..2396c00 --- /dev/null +++ b/app/services/thirdpay/pay.go @@ -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 +} diff --git a/app/services/thirdpay/types/callback.go b/app/services/thirdpay/types/callback.go new file mode 100644 index 0000000..b36419d --- /dev/null +++ b/app/services/thirdpay/types/callback.go @@ -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"` +} diff --git a/app/services/thirdpay/web_pay.go b/app/services/thirdpay/web_pay.go deleted file mode 100644 index 406e060..0000000 --- a/app/services/thirdpay/web_pay.go +++ /dev/null @@ -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 -} diff --git a/app/third/paymentService/payment_service.go b/app/third/paymentService/payment_service.go index 6f5e00b..8ee1499 100644 --- a/app/third/paymentService/payment_service.go +++ b/app/third/paymentService/payment_service.go @@ -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"` diff --git a/app/utils/encrypt/rsa/rsa_test.go b/app/utils/encrypt/rsa/rsa_test.go index 628568e..b3547b8 100644 --- a/app/utils/encrypt/rsa/rsa_test.go +++ b/app/utils/encrypt/rsa/rsa_test.go @@ -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 + ` From 6cfc7c0c0622ebcc441947c883edb69f4c6d3567 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Tue, 6 Aug 2024 17:12:18 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/console/command.go | 5 +++-- app/constants/common/common.go | 10 +++++----- app/http/entities/backend/order.go | 6 +++--- app/http/entities/front/pay.go | 2 +- app/models/orderrequestlogmodel/order_request_log.go | 2 +- app/models/ordersmodel/orders.go | 4 ++-- app/services/thirdpay/types/callback.go | 4 ++-- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/console/command.go b/app/console/command.go index c16692d..63d23b4 100644 --- a/app/console/command.go +++ b/app/console/command.go @@ -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{ @@ -183,7 +184,7 @@ func queryOrder() { // 更新订单状态 todo orderUpdate := ordersmodel.Orders{ Id: orderInfo.Id, - Status: int32(status), + Status: status, } session := ordersmodel.GetInstance().GetDb().NewSession() diff --git a/app/constants/common/common.go b/app/constants/common/common.go index 6d92b4b..a738cc4 100644 --- a/app/constants/common/common.go +++ b/app/constants/common/common.go @@ -29,11 +29,11 @@ const ( ORDER_STATUS_FAILED = 4 ORDER_STATUS_CLOSE = 5 - STATUS_ENABLE int32 = 1 - STATUS_DISABLED int32 = 2 + STATUS_ENABLE = 1 + STATUS_DISABLED = 2 - ORDER_TYPE_PAY int32 = 1 - ORDER_TYPE_REFUND int32 = 2 + ORDER_TYPE_PAY = 1 + ORDER_TYPE_REFUND = 2 PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信 PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝 @@ -57,7 +57,7 @@ var PayChannelList = map[int]string{ PAY_CHANNEL_ALIPAY_JSAPI: "支付宝JSAPI", } -var OrderTypeList = map[int32]string{ +var OrderTypeList = map[int]string{ ORDER_TYPE_PAY: "付款", ORDER_TYPE_REFUND: "退款", } diff --git a/app/http/entities/backend/order.go b/app/http/entities/backend/order.go index 3ea0c6e..f898bf2 100644 --- a/app/http/entities/backend/order.go +++ b/app/http/entities/backend/order.go @@ -112,7 +112,7 @@ type OrderRequestLogResponse struct { MerchantRequest string `json:"merchant_request"` MerchantResponse string `json:"merchant_response"` CreateTime string `json:"create_time"` - Status int32 `json:"status"` + Status int `json:"status"` } func (o *OrderRequestLogResponse) ResponseFromDb(db orderrequestlogmodel.OrderRequestLog) { @@ -133,7 +133,7 @@ type OrderThirdLogResponse struct { 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"` } @@ -142,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.MerchantParam + o.PayParam = db.PayParam o.MerchantCallback = db.MerchantCallback o.CreateTime = db.CreateTime.Format("2006-01-02 15:04:05") } diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index 150f3ff..413970a 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -15,7 +15,7 @@ type PayReqs struct { ApiCommonBody PayChannelId int64 `json:"pay_channel_id" validate:"required" label:"支付渠道"` OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"` - OrderType int32 `json:"order_type" 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:"商品描述"` diff --git a/app/models/orderrequestlogmodel/order_request_log.go b/app/models/orderrequestlogmodel/order_request_log.go index 892fa44..236c759 100644 --- a/app/models/orderrequestlogmodel/order_request_log.go +++ b/app/models/orderrequestlogmodel/order_request_log.go @@ -20,7 +20,7 @@ type OrderRequestLog struct { MerchantResponse string `xorm:"'merchant_response' JSON"` CreateTime time.Time `xorm:"'create_time' datetime created"` UpdateTime time.Time `xorm:"'update_time' timestamp updated"` - Status int32 `xorm:"'status' TINYINT"` + Status int `xorm:"'status' TINYINT"` } // 表名 diff --git a/app/models/ordersmodel/orders.go b/app/models/ordersmodel/orders.go index fc0af91..ed8219a 100644 --- a/app/models/ordersmodel/orders.go +++ b/app/models/ordersmodel/orders.go @@ -18,14 +18,14 @@ type Orders struct { PayChannelId int64 `xorm:"'pay_channel_id' bigint(20)"` AppId int64 `xorm:"'app_id' bigint(20)"` OutTreadNo string `xorm:"'out_tread_no' varchar(50)"` - OrderType int32 `xorm:"'order_type' TINYINT"` + 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 int32 `xorm:"'status' TINYINT"` + Status int `xorm:"'status' TINYINT"` DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"` } diff --git a/app/services/thirdpay/types/callback.go b/app/services/thirdpay/types/callback.go index b36419d..aab4b4a 100644 --- a/app/services/thirdpay/types/callback.go +++ b/app/services/thirdpay/types/callback.go @@ -2,9 +2,9 @@ package types type PayResp struct { OrderNo int64 `json:"order_no"` - OrderType int32 `json:"out_trade_no"` + OrderType int `json:"out_trade_no"` Amount int `json:"order_type"` Desc string `json:"amount"` IsNewCreate bool `json:"is_new_create"` - Status int32 `json:"status"` + Status int `json:"status"` } From 7a887833ad7073e14529cad835047bf4edb0fa63 Mon Sep 17 00:00:00 2001 From: Rzy <465386466@qq.com> Date: Tue, 6 Aug 2024 18:46:05 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=E5=9B=9E=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/errorcode/error_code.go | 13 +- app/services/order.go | 11 ++ app/services/thirdpay/notify/notify.go | 164 +++++++++++++++++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 app/services/thirdpay/notify/notify.go diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 7285e91..2f1a82c 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -35,6 +35,7 @@ const ( AppIpNotAllow = 1202 AppRsaDecryptKeyNotFound = 1203 AppDecryptDataDiscrepancy = 1204 + AppNotifyUrlNotFound = 1205 AppRsaDecryptFail = 1210 AppRsaEncryptKeyNotFound = 1211 AppRsaEncryptFail = 1212 @@ -56,11 +57,16 @@ const ( OrdersNotFound = 1401 OrdersExist = 1402 OrderTypeNotFount = 1403 + OrderIsDelete = 1405 + OrderStatusErr = 1406 //请求日志 RequestLogErrors = 1500 RequestLogNotFound = 1501 RequestResponseValid = 1502 + + //回调 + NotifySendFail = 1600 ) var MsgEN = map[int]string{ @@ -84,7 +90,8 @@ var MsgZH = map[int]string{ AppDisabled: "app通道关闭", AppIpNotAllow: "ip不在白名单内", AppDecryptDataDiscrepancy: "解密数据不一致", - SystemError: "系统错误", + SystemError: "系统错误", + AppNotifyUrlNotFound: "未设置回调地址", AppRsaDecryptKeyNotFound: "密匙缺失,无法进行Rsa解密", AppRsaDecryptFail: "Rsa解密失败", @@ -112,6 +119,10 @@ var MsgZH = map[int]string{ OrdersNotFound: "未找到订单", OrdersExist: "订单已存在", OrderTypeNotFount: "未知的支付方式", + OrderIsDelete: "订单已删除", + OrderStatusErr: "订单状态错误", + + NotifySendFail: "回调发送失败", } var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH} diff --git a/app/services/order.go b/app/services/order.go index 82b4fe4..18c43a5 100644 --- a/app/services/order.go +++ b/app/services/order.go @@ -82,6 +82,17 @@ func OrderCreate(orderIn *ordersmodel.Orders) (orderOut *ordersmodel.Orders, cod 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()) // 拼接查询条件 diff --git a/app/services/thirdpay/notify/notify.go b/app/services/thirdpay/notify/notify.go new file mode 100644 index 0000000..8cad419 --- /dev/null +++ b/app/services/thirdpay/notify/notify.go @@ -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 +}