feat:邮储支付fix
This commit is contained in:
parent
7f2aceb5a7
commit
2543a0fd4d
|
|
@ -46,7 +46,7 @@ func PayUrl(c *gin.Context) {
|
|||
|
||||
res.Order = thirdpay.NewOrdersResp(pay.Order)
|
||||
res.Url = pay.Url
|
||||
res.ThirdMsg = pay.ThirdMsg
|
||||
res.PayInfo = pay.PayInfo
|
||||
res.JsInfo = pay.JsApiInfo
|
||||
controllers.ApiRes(c, res, pay.PayCode)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ type CloseReqs struct {
|
|||
type ApiResponse struct {
|
||||
Order interface{} `json:"order,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
ThirdMsg string `json:"third_msg,omitempty"`
|
||||
JsInfo *WxMiniPayResponse `json:"js_info,omitempty"`
|
||||
PayInfo string `json:"pay_info,omitempty"` // 支付参数,邮储app支付参数
|
||||
}
|
||||
|
||||
type PayChannelListRequest struct {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ type Pay struct {
|
|||
Url string // 支付链接
|
||||
ThirdMsg string // 第三方错误信息
|
||||
JsApiInfo *front.WxMiniPayResponse // jsapi支付参数
|
||||
PayInfo string // 支付参数,邮储app支付参数
|
||||
}
|
||||
|
||||
func NewPayWithPayCheck(paycheck *PayCheck) *Pay {
|
||||
|
|
@ -217,7 +218,7 @@ func (w *Pay) PayUrl() (url string) {
|
|||
}
|
||||
} else if w.PayParam.Channel.ChannelType == common.PAY_CHANNEL_PSBC {
|
||||
// 邮储支付返回 handCodePay 参数
|
||||
w.ThirdMsg = res.Result
|
||||
w.PayInfo = res.Result
|
||||
} else {
|
||||
w.Url = res.Result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,9 +46,8 @@ func (c *Client) BillQuery(date time.Time) (*BillQueryResponse, error) {
|
|||
encryptedBytes, _ := json.Marshal(encryptedReq)
|
||||
url := c.cfg.FileHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
|
||||
|
||||
// head 同时作为 HTTP Header 明文传输
|
||||
head := requestBody["head"].(map[string]string)
|
||||
body, err := c.doPost(url, head, encryptedBytes)
|
||||
// head 同时作为 HTTP Header 明文传输(对齐 YouChuKoffee 的 doPost 方式)
|
||||
body, err := c.doPost(url, BusiMainId, "ufile.query.commonQuery", encryptedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -103,9 +102,8 @@ func (c *Client) BillDownload(fileId string, date time.Time) ([]byte, error) {
|
|||
encryptedBytes, _ := json.Marshal(encryptedReq)
|
||||
url := c.cfg.FileHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
|
||||
|
||||
// head 同时作为 HTTP Header 明文传输
|
||||
head := requestBody["head"].(map[string]string)
|
||||
body, err := c.doPost(url, head, encryptedBytes)
|
||||
// head 同时作为 HTTP Header 明文传输(对齐 YouChuKoffee 的 doPost 方式)
|
||||
body, err := c.doPost(url, BusiMainId, "ufile.download.commonDownload", encryptedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
|
|
@ -16,9 +17,9 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/sm2"
|
||||
psbcutil "PaymentCenter/app/third/paymentService/psbc/internal/util"
|
||||
"github.com/ZZMarquis/gm/sm4"
|
||||
"github.com/tjfoc/gmsm/sm2"
|
||||
"github.com/tjfoc/gmsm/x509"
|
||||
)
|
||||
|
||||
// Client 支付客户端
|
||||
|
|
@ -33,17 +34,23 @@ func NewClient(cfg Config) *Client {
|
|||
|
||||
// doPost 发送 POST 请求到邮储银行
|
||||
// head 信息通过 HTTP Header 明文传输,encryptedBody 作为 HTTP POST Body
|
||||
// 对齐 YouChuKoffee 的 postbank.doPost 流程
|
||||
func (c *Client) doPost(url string, head map[string]string, encryptedBody []byte) ([]byte, error) {
|
||||
// 对齐 YouChuKoffee 的 postbank.doPost 流程(youchu_api.go/config.go)
|
||||
func (c *Client) doPost(url string, partnerTxSriNo string, method string, encryptedBody []byte) ([]byte, error) {
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(encryptedBody))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建请求失败: %v", err)
|
||||
}
|
||||
|
||||
// 构建 HTTP Header,对齐 YouChuKoffee 的 doPost 方式
|
||||
req.Header.Set("partnerTxSriNo", partnerTxSriNo)
|
||||
req.Header.Set("reqTime", time.Now().Format("20060102150405"))
|
||||
req.Header.Set("method", method)
|
||||
req.Header.Set("version", "1")
|
||||
req.Header.Set("merchantId", c.cfg.MerchantId)
|
||||
req.Header.Set("appID", c.cfg.AppID)
|
||||
req.Header.Set("accessType", "API")
|
||||
req.Header.Set("reserve", "")
|
||||
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
|
||||
for k, v := range head {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 60 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
|
|
@ -106,6 +113,7 @@ func RandomNumber(n int) string {
|
|||
|
||||
// EncryptMobile 手机银行支付参数加密
|
||||
// 返回: tysdPayParams(base64), tysdEncryptKey(base64)
|
||||
// 使用 YouChuKoffee 加密包(psbc/internal/sm2 + psbc/internal/util)
|
||||
func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string, error) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
|
|
@ -113,14 +121,14 @@ func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string
|
|||
}
|
||||
}()
|
||||
|
||||
sm4Key := generateSM4Key()
|
||||
sm4Key := psbcutil.GenerateSM4Key()
|
||||
|
||||
// SM2 加密 SM4 密钥(使用银行公钥)
|
||||
bankPubKey, err := x509.ReadPublicKeyFromHex(c.cfg.BankKey)
|
||||
// SM2 加密 SM4 密钥(使用银行公钥,使用 YouChuKoffee 的 Sm2Encrypt)
|
||||
bankPubKey, err := sm2.ReadPublicKeyFromHex(c.cfg.BankKey)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("读取银行公钥失败: %v", err)
|
||||
}
|
||||
encryptKeyBytes, err := sm2.Encrypt(bankPubKey, sm4Key, nil, sm2.C1C3C2)
|
||||
encryptKeyBytes, err := psbcutil.Sm2Encrypt(bankPubKey, sm4Key)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("sm2加密失败: %v", err)
|
||||
}
|
||||
|
|
@ -129,8 +137,8 @@ func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string
|
|||
encryptKeyBytes = encryptKeyBytes[1:]
|
||||
}
|
||||
|
||||
// SM2 签名(与 YouChuKoffee 对齐:UserID 传 nil,默认值 1234567812345678)
|
||||
merchantPrivKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
// SM2 签名(使用 YouChuKoffee 的 Sm2Sign,UserID 传 nil,默认值 1234567812345678)
|
||||
merchantPrivKey, err := sm2.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("读取商户私钥失败: %v", err)
|
||||
}
|
||||
|
|
@ -141,8 +149,10 @@ func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string
|
|||
sig := encodeBase64(rsToBytes(r, s))
|
||||
|
||||
// 拼接参数并 SM4 ECB 加密
|
||||
// 对齐 YouChuKoffee: sm43.ECBEncrypt(sm4Key, sm43.PKCS5Padding([]byte(param), 16))
|
||||
// sm4ECBEncrypt 内部已处理 padding,调用方不需要再 pad
|
||||
param := fmt.Sprintf("%s&sign=%s", inputJson, sig)
|
||||
tmp, err := sm4ECBEncrypt(sm4Key, pkcs5Padding([]byte(param), 16))
|
||||
tmp, err := sm4ECBEncrypt(sm4Key, []byte(param))
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("sm4加密失败: %v", err)
|
||||
}
|
||||
|
|
@ -151,91 +161,113 @@ func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string
|
|||
}
|
||||
|
||||
// DecryptResponse 解密银行响应
|
||||
func (c *Client) DecryptResponse(respJson string, isRequest bool) (string, error) {
|
||||
var reqData map[string]string
|
||||
if err := json.Unmarshal([]byte(respJson), &reqData); err != nil {
|
||||
return "", fmt.Errorf("解析响应JSON失败: %v,响应内容: %s", err, respJson)
|
||||
}
|
||||
|
||||
dataKey := "response"
|
||||
func (c *Client) DecryptResponse(response string, isRequest bool) (Rsponse string, err error) {
|
||||
var MerchantId, PrivateKey, PublicKey string
|
||||
if isRequest {
|
||||
dataKey = "request"
|
||||
MerchantId = c.cfg.MerchantId
|
||||
PrivateKey = c.cfg.PrivateKeyCallback
|
||||
PublicKey = c.cfg.SopPublicKey
|
||||
} else {
|
||||
MerchantId = c.cfg.MerchantId
|
||||
PrivateKey = c.cfg.PrivateKeyCallback
|
||||
PublicKey = c.cfg.SopPublicKey
|
||||
}
|
||||
|
||||
_, hasData := reqData[dataKey]
|
||||
_, hasSignature := reqData["signature"]
|
||||
_, hasEncryptKey := reqData["encryptKey"]
|
||||
|
||||
if !hasData || !hasSignature || !hasEncryptKey {
|
||||
if code, ok := reqData["code"]; ok {
|
||||
msg := reqData["msg"]
|
||||
if msg == "" {
|
||||
msg = reqData["message"]
|
||||
}
|
||||
return "", fmt.Errorf("银行返回错误,错误码: %s,错误信息: %s", code, msg)
|
||||
}
|
||||
if respCode, ok := reqData["respCode"]; ok {
|
||||
respMsg := reqData["respMsg"]
|
||||
return "", fmt.Errorf("银行返回错误,错误码: %s,错误信息: %s", respCode, respMsg)
|
||||
}
|
||||
missingFields := []string{}
|
||||
if !hasData {
|
||||
missingFields = append(missingFields, dataKey)
|
||||
}
|
||||
if !hasSignature {
|
||||
missingFields = append(missingFields, "signature")
|
||||
}
|
||||
if !hasEncryptKey {
|
||||
missingFields = append(missingFields, "encryptKey")
|
||||
}
|
||||
return "", fmt.Errorf("响应格式不正确,缺少字段: %v,响应内容: %s", missingFields, respJson)
|
||||
}
|
||||
|
||||
reqData["accessToken"] = ""
|
||||
inData := reqData[dataKey]
|
||||
inSignature := reqData["signature"]
|
||||
inEncryptKey := reqData["encryptKey"]
|
||||
|
||||
// 验签
|
||||
checked := c.verify(fmt.Sprintf("%s%s%s", inData, inEncryptKey, ""), inSignature)
|
||||
if !checked {
|
||||
return "", fmt.Errorf("签名验证失败")
|
||||
}
|
||||
|
||||
// 解密 SM4 密钥
|
||||
privKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
encrypt, err := Decrypt(MerchantId, PrivateKey, PublicKey, response, isRequest)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取私钥失败: %v", err)
|
||||
return
|
||||
}
|
||||
var RsponseData map[string]interface{}
|
||||
err = json.Unmarshal([]byte(encrypt), &RsponseData)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
} else {
|
||||
if RsponseData["body"] != nil {
|
||||
if body, ok := RsponseData["body"].(string); ok {
|
||||
Rsponse = body
|
||||
} else {
|
||||
notify, _ := json.Marshal(RsponseData["body"].(map[string]interface{}))
|
||||
Rsponse = string(notify)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func Decrypt(merchantId, privateKey, sopPublicKey, respJson string, isRequest bool) (string, error) {
|
||||
var reqData map[string]string
|
||||
err := json.Unmarshal([]byte(respJson), &reqData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
reqData["accessToken"] = ""
|
||||
keys := [4]string{}
|
||||
if isRequest {
|
||||
keys = [4]string{"request", "signature", "encryptKey", "accessToken"}
|
||||
} else {
|
||||
keys = [4]string{"response", "signature", "encryptKey", "accessToken"}
|
||||
}
|
||||
var inEncryptKey, inAccessToken, inData, inSignature string
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
data, err := checkInData(reqData, keys[i])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch keys[i] {
|
||||
case "request", "response":
|
||||
inData = data
|
||||
case "signature":
|
||||
inSignature = data
|
||||
case "encryptKey":
|
||||
inEncryptKey = data
|
||||
case "accessToken":
|
||||
inAccessToken = data
|
||||
}
|
||||
}
|
||||
|
||||
checked := verify(fmt.Sprintf("%s%s%s", inData, inEncryptKey, inAccessToken), inSignature, sopPublicKey, merchantId)
|
||||
if !checked {
|
||||
return "", errors.New("签名验证失败")
|
||||
}
|
||||
|
||||
priKey, err := sm2.ReadPrivateKeyFromHex(privateKey)
|
||||
if err != nil {
|
||||
return "", errors.New("读取私钥失败")
|
||||
}
|
||||
hexEncryptKey, err := hex.DecodeString(inEncryptKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("解密sm4key失败: %v", err)
|
||||
return "", errors.New("解密sm4key失败")
|
||||
}
|
||||
sm4Key, err := sm2.Decrypt(privKey, hexEncryptKey, sm2.C1C3C2)
|
||||
sm4Key, err := psbcutil.Sm2Decrypt(priKey, hexEncryptKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("解密sm2key失败: %v", err)
|
||||
return "", errors.New("解密sm2key失败")
|
||||
}
|
||||
|
||||
// 解密数据
|
||||
request, _ := base64.StdEncoding.DecodeString(inData)
|
||||
encryptedSm4Key, err := sm4.CBCDecrypt(sm4Key, getSM4IV(), request)
|
||||
decryptedStr := string(pkcs5UnPadding(encryptedSm4Key))
|
||||
|
||||
// 提取 body 字段(银行解密后的结构为 {head, body},业务数据在 body 中)
|
||||
var decryptedMap map[string]interface{}
|
||||
if jsonErr := json.Unmarshal([]byte(decryptedStr), &decryptedMap); jsonErr == nil {
|
||||
if bodyVal, bodyOk := decryptedMap["body"]; bodyOk && bodyVal != nil {
|
||||
if bodyStr, isStr := bodyVal.(string); isStr {
|
||||
return bodyStr, nil
|
||||
}
|
||||
bodyBytes, marshalErr := json.Marshal(bodyVal)
|
||||
if marshalErr == nil {
|
||||
return string(bodyBytes), nil
|
||||
}
|
||||
}
|
||||
encryptedSm4Key, err := sm4.CBCDecrypt(sm4Key, psbcutil.GetSM4IV(), request)
|
||||
|
||||
return string(psbcutil.Padding(encryptedSm4Key, 0)), nil
|
||||
}
|
||||
|
||||
return decryptedStr, nil
|
||||
func checkInData(reqData map[string]string, key string) (string, error) {
|
||||
data, ok := reqData[key]
|
||||
if !ok {
|
||||
return "", errors.New("请求数据中不存在" + key)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func verify(content string, signature string, publicKeyStr string, merchantId string) bool {
|
||||
pubKey, err := sm2.ReadPublicKeyFromHex(publicKeyStr)
|
||||
//content = ""
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("pubKeyBytes sm2 ReadPublicKeyFromHex err: %v", err))
|
||||
}
|
||||
r, s := signToRS(signature)
|
||||
return sm2.Sm2Verify(pubKey, []byte(content), []byte(merchantId), r, s)
|
||||
}
|
||||
|
||||
// VerifySignature 验签
|
||||
|
|
@ -244,7 +276,7 @@ func (c *Client) VerifySignature(content, signature string) bool {
|
|||
}
|
||||
|
||||
func (c *Client) verify(content, signature string) bool {
|
||||
pubKey, err := x509.ReadPublicKeyFromHex(c.cfg.SopPublicKey)
|
||||
pubKey, err := sm2.ReadPublicKeyFromHex(c.cfg.SopPublicKey)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("pubKeyBytes sm2 ReadPublicKeyFromHex err: %v", err))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ import (
|
|||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"PaymentCenter/app/third/paymentService/psbc/internal/sm2"
|
||||
psbcutil "PaymentCenter/app/third/paymentService/psbc/internal/util"
|
||||
"github.com/ZZMarquis/gm/sm4"
|
||||
"github.com/tjfoc/gmsm/sm2"
|
||||
"github.com/tjfoc/gmsm/x509"
|
||||
)
|
||||
|
||||
// EncryptRequest 加密请求
|
||||
|
|
@ -30,11 +31,11 @@ func EncryptRequest(request interface{}, cfg Config) (map[string]string, error)
|
|||
return nil, fmt.Errorf("序列化请求失败: %v", err)
|
||||
}
|
||||
inputJson := string(inputBytes)
|
||||
|
||||
// Step 2: SM4 CBC 加密
|
||||
sm4Key := generateSM4Key()
|
||||
iv := getSM4IV()
|
||||
paddedData := pkcs5Padding([]byte(inputJson), sm4.BlockSize)
|
||||
sm4Key := psbcutil.GenerateSM4Key()
|
||||
|
||||
iv := psbcutil.GetSM4IV() // UISwD9fW6cFh9SNS
|
||||
paddedData := psbcutil.Padding([]byte(inputJson), 1)
|
||||
tmp, err := sm4.CBCEncrypt(sm4Key, iv, paddedData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("SM4加密失败: %v", err)
|
||||
|
|
@ -42,12 +43,12 @@ func EncryptRequest(request interface{}, cfg Config) (map[string]string, error)
|
|||
responseMsg := base64.StdEncoding.EncodeToString(tmp)
|
||||
responseMsg = addNewline(responseMsg) // 对齐 YouChuKoffee,每76字符加 \r\n
|
||||
|
||||
// Step 3: SM2 加密 SM4 密钥
|
||||
sopPubKey, err := x509.ReadPublicKeyFromHex(cfg.SopPublicKey)
|
||||
// Step 3: SM2 加密 SM4 密钥(使用 copied sm2 包,对齐 YouChuKoffee 的 Sm2Encrypt)
|
||||
sopPubKey, err := sm2.ReadPublicKeyFromHex(cfg.SopPublicKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取SOP公钥失败: %v", err)
|
||||
}
|
||||
encryptKeyBytes, err := sm2.Encrypt(sopPubKey, sm4Key, rand.Reader, sm2.C1C3C2)
|
||||
encryptKeyBytes, err := psbcutil.Sm2Encrypt(sopPubKey, sm4Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("SM2加密SM4密钥失败: %v", err)
|
||||
}
|
||||
|
|
@ -55,7 +56,8 @@ func EncryptRequest(request interface{}, cfg Config) (map[string]string, error)
|
|||
|
||||
// Step 4: 签名(对齐 YouChuKoffee sign():UserID = MerchantId)
|
||||
signContent := fmt.Sprintf("%s%s%s", responseMsg, encryptKey, accessToken)
|
||||
signature, err := client.signWithUserID(signContent, []byte(cfg.MerchantId))
|
||||
|
||||
signature, err := sign(cfg.MerchantId, client.cfg.PrivateKeyCallback, signContent)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("生成签名失败: %v", err)
|
||||
}
|
||||
|
|
@ -71,16 +73,23 @@ func EncryptRequest(request interface{}, cfg Config) (map[string]string, error)
|
|||
|
||||
// signWithUserID 使用指定 UserID 对内容进行 SM2 签名
|
||||
// 对齐 YouChuKoffee 的 sign() + rSToSign():直接返回 r.Text(16) + "#" + s.Text(16),不做 base64 编码
|
||||
func (c *Client) signWithUserID(content string, userId []byte) (string, error) {
|
||||
privKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
func sign(merchantId string, privateKeyHex string, signContent string) (string, error) {
|
||||
privateKey, err := sm2.ReadPrivateKeyFromHex(privateKeyHex)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取私钥失败: %v", err)
|
||||
return "", err
|
||||
}
|
||||
r, s, err := sm2.Sm2Sign(privKey, []byte(content), userId, rand.Reader)
|
||||
|
||||
r, s, err := sm2.Sm2Sign(privateKey, []byte(signContent), []byte(merchantId), rand.Reader)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("SM2签名失败: %v", err)
|
||||
return "", err
|
||||
}
|
||||
return r.Text(16) + "#" + s.Text(16), nil
|
||||
return rSToSign(r, s), nil
|
||||
}
|
||||
|
||||
func rSToSign(r *big.Int, s *big.Int) string {
|
||||
rStr := r.Text(16)
|
||||
sStr := s.Text(16)
|
||||
return fmt.Sprintf("%s#%s", rStr, sStr)
|
||||
}
|
||||
|
||||
// addNewline 每76个字符添加 \r\n,对齐 YouChuKoffee 的 postbank.addNewline
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func (c *Client) OrderQuery(orderNo string) (*OrderQueryResponse, error) {
|
|||
"sourceId": "16",
|
||||
"reqTraceId": now + RandomNumber(10),
|
||||
"reqDate": now, // 14 位 YYYYMMDDHHmmss
|
||||
"txnDt": now,
|
||||
"txnDt": time.Now().Format("20060102"), // 8 位 YYYYMMDD,对齐 YouChuKoffee
|
||||
"mchtNo": c.cfg.MchtNo,
|
||||
"oldSeqNo": orderNo,
|
||||
},
|
||||
|
|
@ -48,12 +48,13 @@ func (c *Client) OrderQuery(orderNo string) (*OrderQueryResponse, error) {
|
|||
return nil, fmt.Errorf("加密请求失败: %v", err)
|
||||
}
|
||||
|
||||
BusiMainId = "202607301754241710448735"
|
||||
|
||||
encryptedBytes, _ := json.Marshal(encryptedReq)
|
||||
url := c.cfg.OrderHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
|
||||
|
||||
// head 同时作为 HTTP Header 明文传输
|
||||
head := requestBody["head"].(map[string]string)
|
||||
body, err := c.doPost(url, head, encryptedBytes)
|
||||
// head 同时作为 HTTP Header 明文传输(对齐 YouChuKoffee 的 doPost 方式)
|
||||
body, err := c.doPost(url, BusiMainId, "b2c.gatewaypay.orderQuery", encryptedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@ func (c *Client) Refund(req RefundRequest) (*RefundResponse, error) {
|
|||
encryptedBytes, _ := json.Marshal(encryptedReq)
|
||||
url := c.cfg.OrderHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
|
||||
|
||||
// head 同时作为 HTTP Header 明文传输
|
||||
head := requestBody["head"].(map[string]string)
|
||||
body, err := c.doPost(url, head, encryptedBytes)
|
||||
// head 同时作为 HTTP Header 明文传输(对齐 YouChuKoffee 的 doPost 方式)
|
||||
body, err := c.doPost(url, BusiMainId, "b2c.gatewaypay.orderRefund", encryptedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ type Config struct {
|
|||
FileHost string
|
||||
ShopId string
|
||||
Psbcmcc string // 三方服务商标识,如 LSXD、JBZ
|
||||
PrivateKeyCallback string // 邮储响应解密的私钥
|
||||
}
|
||||
|
||||
// PaymentLinkRequest 生成支付链接请求
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ type PsbcPay struct {
|
|||
AppID string `json:"app_id"` // 应用ID
|
||||
SopPublicKey string `json:"sop_public_key"` // SOP公钥
|
||||
PrivateKey string `json:"private_key"` // 商户私钥
|
||||
PrivateKeyCallback string `json:"private_key_callback"` // 邮储响应解密的私钥
|
||||
Pubkey string `json:"pubkey"` // 商户公钥
|
||||
BankKey string `json:"bank_key"` // 银行公钥
|
||||
Sha string `json:"sha"` // SHA密钥
|
||||
|
|
@ -50,6 +51,7 @@ func PsbcInitClient(psbcConfig PsbcPay) *psbc.Client {
|
|||
FileHost: psbcConfig.FileHost,
|
||||
ShopId: psbcConfig.ShopId,
|
||||
Psbcmcc: psbcConfig.Psbcmcc,
|
||||
PrivateKeyCallback: psbcConfig.PrivateKeyCallback,
|
||||
}
|
||||
return psbc.NewClient(cfg)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ func TestPsbcPay(t *testing.T) {
|
|||
AppID: "961925472724332544001",
|
||||
SopPublicKey: "04CABE03249C94BDC8A6A4440DA1B2ADFACF73F4340E5F1B9A76463694B44C2E5600A9BEAA035739383C292CF9F1C4695FAAC7963CD5033D5D647A6B1EBE78EC6A",
|
||||
PrivateKey: "140c5c68da1829b79d8e4629a8b9548bd694ccc7061fbacb1079aed0e5ac33fa",
|
||||
PrivateKeyCallback: "1F0E2F085955461A9B87820AFBD513712CAEA89687BE657DE4EC91613BE62D32",
|
||||
Pubkey: "0447fe9ed13aac6200c92b893ad1289a98437c8404e64b1d2f7c755698a8b8e8acb35c1db2bedc5213c930bdfc10efb0e12269cf6a06877679f114fe5ae9dd4469",
|
||||
BankKey: "04E0E2E37F11901483CDFBC47F489D87D5D78C55DD7F919B73DEA83007748668B7871A1BA9608F156E25B7D64C7821379BAC1E2C591D5A50FF311D1AAE026C1DAE",
|
||||
Sha: "636879vrt96t57w6f59",
|
||||
|
|
@ -69,18 +70,18 @@ func TestPsbcPay(t *testing.T) {
|
|||
PayerClientIp: "192.168.110.235",
|
||||
Psbc: psbc,
|
||||
}
|
||||
//支付
|
||||
orderResult := PaymentService(c, request)
|
||||
t.Log(orderResult)
|
||||
////支付
|
||||
//orderResult := PaymentService(c, request)
|
||||
//t.Log(orderResult)
|
||||
|
||||
//// 查询订单
|
||||
//qreq := PayOrderQueryRequest{
|
||||
// OrderId: request.OrderId,
|
||||
// PayChannel: 3,
|
||||
// Psbc: request.Psbc,
|
||||
//}
|
||||
//queryResult := PayOrderQuery(c, qreq)
|
||||
//t.Log(queryResult)
|
||||
// 查询订单
|
||||
qreq := PayOrderQueryRequest{
|
||||
OrderId: request.OrderId,
|
||||
PayChannel: 3,
|
||||
Psbc: request.Psbc,
|
||||
}
|
||||
queryResult := PayOrderQuery(c, qreq)
|
||||
t.Log(queryResult)
|
||||
|
||||
//// 退款
|
||||
//refund := OrderRefundRequest{
|
||||
|
|
|
|||
Loading…
Reference in New Issue