增加下游回调日志记录

This commit is contained in:
wolter 2024-08-08 17:55:26 +08:00
parent f6bdfdf84c
commit 5e0627a0f3
9 changed files with 112 additions and 361 deletions

View File

@ -7,8 +7,6 @@ import (
"PaymentCenter/app/http/entities"
"PaymentCenter/app/http/entities/backend"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/models/orderthirdpaylogmodel"
"PaymentCenter/app/models/paychannelmodel"
"PaymentCenter/app/services/thirdpay/thirdpay_notify"
"PaymentCenter/app/third/paymentService"
"PaymentCenter/app/third/paymentService/payCommon"
@ -16,6 +14,7 @@ import (
"PaymentCenter/config"
"context"
"encoding/json"
"fmt"
"github.com/qit-team/snow-core/command"
"strconv"
"sync"
@ -86,6 +85,12 @@ func closeOrder() {
utils.Log(nil, "关闭订单,上游失败", response, orderInfo.Id)
}
orderIds = append(orderIds, orderInfo.Id)
// 回调通知下游
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, common.ORDER_STATUS_CLOSE, 0, "长时间未支付关闭订单")
//utils.Log(nil, "主动查询订单支付状态,回调下游", notifyResult)
if notifyResult.ErrCode != errorcode.Success {
utils.Log(nil, "关闭订单,回调下游失败", fmt.Sprintf("%#v", notifyResult))
}
}
// 修改订单状态为关闭
cond = builder.NewCond()
@ -190,24 +195,7 @@ func queryOrder() {
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, status, int(result.Result.PayerTotal), msg)
//utils.Log(nil, "主动查询订单支付状态,回调下游", notifyResult)
if notifyResult.ErrCode != errorcode.Success {
utils.Log(nil, "主动查询订单支付状态,回调下游失败", notifyResult)
}
payCallback, _ := json.Marshal(result)
merchantCallback, _ := json.Marshal(notifyResult)
thirdRepo := data.NewOrderThirdPayLogRepo(paychannelmodel.GetInstance().GetDb())
log := orderthirdpaylogmodel.OrderThirdPayLog{
OrderId: orderInfo.Id,
PayCallback: string(payCallback),
Status: 1,
PayParam: "",
MerchantCallback: string(merchantCallback),
Type: common.THIRD_ORDER_TYPE_CALL_BACK,
}
// 写日志
_, err = thirdRepo.OrderThirdPayLogInsertOne(&log)
if err != nil {
utils.Log(nil, "主动查询订单支付状态,记录回调日志失败", log.OrderId, err)
utils.Log(nil, "主动查询订单支付状态,回调下游失败", fmt.Sprintf("%#v", notifyResult))
}
}
}(orderInfo)
@ -312,23 +300,6 @@ func queryRefundOrder() {
if notifyResult.ErrCode != errorcode.Success {
utils.Log(nil, "查询退款订单状态,回调下游失败", notifyResult)
}
payCallback, _ := json.Marshal(result)
merchantCallback, _ := json.Marshal(notifyResult)
thirdRepo := data.NewOrderThirdPayLogRepo(paychannelmodel.GetInstance().GetDb())
log := orderthirdpaylogmodel.OrderThirdPayLog{
OrderId: orderInfo.Id,
PayCallback: string(payCallback),
Status: 1,
PayParam: "",
MerchantCallback: string(merchantCallback),
Type: common.THIRD_ORDER_TYPE_CALL_BACK,
}
// 写日志
_, err = thirdRepo.OrderThirdPayLogInsertOne(&log)
if err != nil {
utils.Log(nil, "查询退款订单状态,记录回调日志失败", log.OrderId, err)
}
}
}(orderInfo)
}

View File

@ -0,0 +1,39 @@
package data
import (
"PaymentCenter/app/http/entities"
"PaymentCenter/app/models/ordercallbacklogmodel"
"xorm.io/builder"
"xorm.io/xorm"
)
type OrderCallbackLogRepo struct {
repo xorm.Interface
}
func NewOrderCallbackLogRepo(repo xorm.Interface) *OrderCallbackLogRepo {
return &OrderCallbackLogRepo{
repo: repo,
}
}
func (m *OrderCallbackLogRepo) OrderCallbackLogList(conn builder.Cond, pageFilter entities.PageRequest, orderLogList *[]ordercallbacklogmodel.OrderCallbackLog) (int64, error) {
repo := m.repo.Where(conn)
if pageFilter.Page > 0 {
repo = repo.Limit(pageFilter.PageSize, pageFilter.PageSize*(pageFilter.Page-1))
}
return repo.Desc("create_time").FindAndCount(orderLogList)
}
func (m *OrderCallbackLogRepo) OrderCallbackLogInsertOne(orderLog *ordercallbacklogmodel.OrderCallbackLog) (int64, error) {
return m.repo.InsertOne(orderLog)
}
func (m *OrderCallbackLogRepo) OrderCallbackLogDelete(orderLog *ordercallbacklogmodel.OrderCallbackLog, conn builder.Cond) (int64, error) {
return m.repo.Where(conn).Delete(orderLog)
}
// columns 参数为要更新的字段
func (m *OrderCallbackLogRepo) OrderCallbackLogUpdate(orderLog *ordercallbacklogmodel.OrderCallbackLog, conn builder.Cond, columns ...string) (int64, error) {
return m.repo.Where(conn).MustCols(columns...).Update(orderLog)
}

View File

@ -0,0 +1,41 @@
package ordercallbacklogmodel
import (
"github.com/qit-team/snow-core/db"
"sync"
"time"
)
var (
once sync.Once
m *OrderCallbackLogModel
)
// 实体
type OrderCallbackLog struct {
Id int64 `xorm:"'id' bigint(20) pk autoincr"`
OrderId int64 `xorm:"'order_id' bigint(20)"`
MerchantRequest string `xorm:"'merchant_request' JSON"`
Status int `xorm:"'status' int(11)"`
MerchantResponse string `xorm:"'merchant_response' JSON"`
CreateTime time.Time `xorm:"'create_time' datetime created"`
}
// 表名
func (m *OrderCallbackLog) TableName() string {
return "order_callback_log"
}
// 私有化防止被外部new
type OrderCallbackLogModel struct {
db.Model //组合基础Model集成基础Model的属性和方法
}
// 单例模式
func GetInstance() *OrderCallbackLogModel {
once.Do(func() {
m = new(OrderCallbackLogModel)
//m.DiName = "" //设置数据库实例连接默认db.SingletonMain
})
return m
}

View File

@ -103,7 +103,7 @@ func OrderFindOne(order *ordersmodel.Orders, conn builder.Cond, col ...string) (
}
return nil, errorcode.SystemError
}
return orderInfo, errorcode.OrdersExist
return orderInfo, errorcode.Success
}
func PayOrderCheckRepeat(order *ordersmodel.Orders, conn builder.Cond) (exist bool, code int) {

View File

@ -3,10 +3,13 @@ package thirdpay_notify
import (
"PaymentCenter/app/constants/common"
"PaymentCenter/app/constants/errorcode"
"PaymentCenter/app/data"
"PaymentCenter/app/http/entities"
"PaymentCenter/app/models/appmodel"
"PaymentCenter/app/models/ordercallbacklogmodel"
"PaymentCenter/app/models/ordersmodel"
"PaymentCenter/app/services"
"PaymentCenter/app/utils"
"PaymentCenter/app/utils/httpclient"
"github.com/bytedance/sonic"
"time"
@ -91,7 +94,10 @@ func (o *OrderNotify) Handle() (res *OrderNotifyResp) {
}
}
// 发送下游回调通知
func (o *OrderNotify) sendNotify(body *OrderNotifySendContent) {
var callbackStatus = common.STATUS_ENABLE
var response string
bodyByte, _ := sonic.Marshal(&body)
headers := make(map[string]string, 1)
@ -99,7 +105,24 @@ func (o *OrderNotify) sendNotify(body *OrderNotifySendContent) {
resByte, err := httpclient.FastHttpPost(o.app.NotifyUrl, headers, bodyByte, 0)
if err != nil || string(resByte) != "success" {
o.Code = errorcode.NotifySendFail
callbackStatus = common.STATUS_DISABLED
response = "url=" + o.app.NotifyUrl + "|error=" + err.Error()
}
response = string(resByte) + response
// 记录回调日志
go func(orderId int64, status int, request, response string) {
repo := data.NewOrderCallbackLogRepo(ordercallbacklogmodel.GetInstance().GetDb())
log := ordercallbacklogmodel.OrderCallbackLog{
OrderId: orderId,
MerchantRequest: string(bodyByte),
Status: status,
MerchantResponse: response,
}
_, insertErr := repo.OrderCallbackLogInsertOne(&log)
if insertErr != nil {
utils.Log(nil, "回调写入日志error", insertErr)
}
}(o.OrderId, callbackStatus, string(bodyByte), response)
return
}

View File

@ -1,90 +0,0 @@
package market
import (
"PaymentCenter/config"
"bytes"
"encoding/json"
"github.com/pkg/errors"
"io/ioutil"
"net/http"
)
type MarketClient struct {
cfg config.MarketConfig
}
type MarketSendRequest struct {
AppId string `json:"app_id"` //APP ID
Sign string `json:"sign"` //签名
ReqCode string `json:"req_code"` //固定值voucher.create
MemId string `json:"mem_id"` //商户号
ReqSerialNo string `json:"req_serial_no"` //请求唯一流水号 最大32位
TimeTamp string `json:"timestamp"` //时间戳 yyyyMMddHHmmss
PosId string `json:"pos_id"` //商户方平台号
VoucherId string `json:"voucher_id"` //制码批次号
VoucherNum int `json:"voucher_num"` //请券数量,默认是 1
MobileNo string `json:"mobile_no"` //11 手机号,可传空字符串
SendMsg string `json:"send_msg"` //是否发送短信2- 发送 1-不发送
}
type MarketSenResponse struct {
VoucherId string `json:"voucher_id"` //制码批次号
VoucherCode string `json:"voucher_code"` //券码
ShortUrl string `json:"short_url"` //含二维码、条码的短链接
VoucherSdate string `json:"voucher_sdate"` //有效期起
VoucherEdate string `json:"voucher_edate"` //有效期止
CodeType string `json:"code_type"` //码类型: 00- 代金券 01- 满减券
}
type MarketResponse struct {
ErrCode string `json:"errCode"` //00-成功 其他:失败
Msg string `json:"msg"` //描 述 (失败时必填)
Data MarketSenResponse `json:"data"`
}
func (this *MarketSendRequest) toMap() (resultMap map[string]interface{}) {
// Marshal the struct to JSON, ignoring omitempty fields.
jsonBytes, err := json.Marshal(this)
if err != nil {
return
}
// Unmarshal the JSON into a map to get the final result.
err = json.Unmarshal(jsonBytes, &resultMap)
if err != nil {
return
}
return resultMap
}
func (this *MarketClient) doPost(url string, jsonBytes []byte) (body []byte, err error) {
// 创建POST请求
url = this.cfg.Host + url
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
if err != nil {
return
}
// 设置Content-Type头
req.Header.Set("Content-Type", "application/json")
// 创建HTTP客户端
client := &http.Client{}
// 发送请求并处理响应
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
// 读取响应体
if resp.StatusCode != http.StatusOK {
err = errors.New("HTTP request failed: " + resp.Status)
return
}
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
return
}
return
}

View File

@ -1,62 +0,0 @@
package market
import (
"PaymentCenter/app/utils/encrypt"
"PaymentCenter/config"
"encoding/json"
"time"
)
func NewMarketClient(cfg config.MarketConfig) *MarketClient {
cfg.Sign = "-----BEGIN RSA PRIVATE KEY-----\n" + cfg.Sign + "\n-----END RSA PRIVATE KEY-----"
return &MarketClient{
cfg: cfg,
}
}
/*
MarketSend
券码生成接口
- 请求地址/openApi/v1/market/key/send
- 说明发券接口应支持使用同一流水号进行重复请求当调用该接口失败时 以使用同一流水号进行再次请求接口需要根据请求的流水号进行判断若无该流水 号的券码信息则新生成后返回若有该流水号的券码信息则直接返回该券码的信息
orderNo: 订单号
VoucherId: 制码批次号
MobileNo: 11 手机号可传空字符串
SendMsg: 是否发送短信2- 发送 1-不发送
*/
func (this *MarketClient) MarketSend(orderNo, VoucherId, MobileNo, SendMsg string) (res MarketResponse, err error) {
url := "/openApi/v1/market/key/send"
request := MarketSendRequest{
AppId: this.cfg.AppId,
ReqCode: this.cfg.ReqCode,
MemId: this.cfg.MemId,
PosId: this.cfg.PosId,
TimeTamp: time.Now().Format("20060102150405"),
VoucherId: VoucherId,
ReqSerialNo: orderNo,
VoucherNum: 1,
MobileNo: MobileNo,
SendMsg: SendMsg,
}
request.Sign, err = MakeRsaSign(this.cfg.Sign, request.toMap())
if err != nil {
return res, err
}
bytes, err := json.Marshal(request)
if err != nil {
return res, err
}
data, err := this.doPost(url, bytes)
if err != nil {
return res, err
}
err = json.Unmarshal(data, &res)
// 加密
if len(res.Data.ShortUrl) > 0 {
res.Data.ShortUrl = encrypt.AesEncryptCBC([]byte(res.Data.ShortUrl), []byte(this.cfg.SecretKey))
}
return res, err
}

View File

@ -1,34 +0,0 @@
package market
import (
"PaymentCenter/app/utils"
"PaymentCenter/config"
"fmt"
"github.com/qit-team/snow-core/kernel/server"
"os"
"testing"
)
func TestMarketSendRequest_Market(t *testing.T) {
opts := config.GetOptions()
if opts.ShowVersion {
fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate)
os.Exit(0)
}
//加载配置
conf, err := config.Load(opts.ConfFile)
if err != nil {
utils.Log(nil, "err", err.Error())
return
}
client := NewMarketClient(conf.OpenApiMarketConfig)
//data, err := client.MarketSend("123456789111", "1717567048171", "", "2")
data, err := client.MarketSend("123111", "1717", "", "2")
if err != nil {
t.Error(err)
}
t.Log(data)
}

View File

@ -1,137 +0,0 @@
package market
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"sort"
)
// getSignString 使用 xx=aa&yy=bb 的字符串拼接
func getSignString(data map[string]interface{}) string {
keys := make([]string, 0, len(data))
for key := range data {
keys = append(keys, key)
}
sort.Strings(keys)
signString := ""
separator := ""
for _, key := range keys {
value := data[key]
if key == "sign" || value == nil {
continue
}
signString += fmt.Sprintf("%s%s=%v", separator, key, value)
separator = "&"
}
return signString
}
// VerifyRsaSign 签名验证
func VerifyRsaSign(publicKey string, data map[string]interface{}) (map[string]interface{}, error) {
// 对 sign nonce timestamp appId 升序排序
// 使用 xx=aa&yy=bb 的字符串拼接
// 商户的公钥验签 RSA2验签
signString := getSignString(data)
rsaPubKey, err := parseRSAPublicKeyFromPEM([]byte(publicKey))
if err != nil {
return nil, err
}
signature, err := base64.StdEncoding.DecodeString(data["sign"].(string))
if err != nil {
return nil, err
}
hashed := sha256.Sum256([]byte(signString))
err = rsa.VerifyPKCS1v15(rsaPubKey, crypto.SHA256, hashed[:], signature)
if err != nil {
return nil, errors.New("签名验证失败")
}
return data, nil
}
// MakeRsaSign 生成签名
func MakeRsaSign(privateKey string, data map[string]interface{}) (string, error) {
// 对 sign nonce timestamp appId 升序排序
// 使用 xx=aa&yy=bb 的字符串拼接
// 营销系统生成的私钥生成签名 RSA2加签
signString := getSignString(data)
privKey, err := parseRSAPrivateKeyFromPEM([]byte(privateKey))
if err != nil {
return "", errors.New("私钥解析失败")
}
hashed := sha256.Sum256([]byte(signString))
signature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, hashed[:])
if err != nil {
return "", errors.New("签名失败")
}
return base64.StdEncoding.EncodeToString(signature), nil
}
// ParseRSAPrivateKeyFromPEM 解析私钥
func parseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
var err error
// Parse PEM block
var block *pem.Block
if block, _ = pem.Decode(key); block == nil {
return nil, errors.New("私钥解析失败: 无效的PEM格式")
}
var parsedKey interface{}
if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
return nil, err
}
}
var pkey *rsa.PrivateKey
var ok bool
if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
return nil, errors.New("密钥不是有效的RSA私钥")
}
return pkey, nil
}
// parseRSAPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
func parseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
var err error
// Parse PEM block
var block *pem.Block
if block, _ = pem.Decode(key); block == nil {
return nil, errors.New("公钥解析失败: 无效的PEM格式")
}
// Parse the key
var parsedKey interface{}
if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
parsedKey = cert.PublicKey
} else {
return nil, err
}
}
var pkey *rsa.PublicKey
var ok bool
if pkey, ok = parsedKey.(*rsa.PublicKey); !ok {
return nil, errors.New("密钥不是有效的RSA公钥")
}
return pkey, nil
}