feat:邮储支付代码完善补充缺失逻辑
This commit is contained in:
parent
a2202ea200
commit
80bdf8b00a
|
|
@ -54,14 +54,18 @@ func (c *Client) BillQuery(date time.Time) (*BillQueryResponse, error) {
|
|||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP请求失败,状态码: %d,响应: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
responseData, err := c.DecryptResponse(string(body), false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解密响应失败: %v", err)
|
||||
return nil, fmt.Errorf("解密响应失败: %v,原始响应: %s", err, string(body))
|
||||
}
|
||||
|
||||
var result BillQueryResponse
|
||||
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v", err)
|
||||
return nil, fmt.Errorf("解析响应失败: %v,响应内容: %s", err, responseData)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
|
|
@ -109,5 +113,9 @@ func (c *Client) BillDownload(fileId string, date time.Time) ([]byte, error) {
|
|||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP请求失败,状态码: %d,响应: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,32 +118,47 @@ func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string
|
|||
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 "", err
|
||||
return "", fmt.Errorf("解析响应JSON失败: %v,响应内容: %s", err, respJson)
|
||||
}
|
||||
|
||||
dataKey := "response"
|
||||
if isRequest {
|
||||
dataKey = "request"
|
||||
}
|
||||
|
||||
_, 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"] = ""
|
||||
var keys []string
|
||||
if isRequest {
|
||||
keys = []string{"request", "signature", "encryptKey", "accessToken"}
|
||||
} else {
|
||||
keys = []string{"response", "signature", "encryptKey", "accessToken"}
|
||||
}
|
||||
|
||||
var inEncryptKey, inData, inSignature string
|
||||
for _, key := range keys {
|
||||
data, ok := reqData[key]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("请求数据中不存在%s", key)
|
||||
}
|
||||
switch key {
|
||||
case "request", "response":
|
||||
inData = data
|
||||
case "signature":
|
||||
inSignature = data
|
||||
case "encryptKey":
|
||||
inEncryptKey = data
|
||||
}
|
||||
}
|
||||
inData := reqData[dataKey]
|
||||
inSignature := reqData["signature"]
|
||||
inEncryptKey := reqData["encryptKey"]
|
||||
|
||||
// 验签
|
||||
checked := c.verify(fmt.Sprintf("%s%s%s", inData, inEncryptKey, ""), inSignature)
|
||||
|
|
@ -213,7 +228,12 @@ func getSM4IV() []byte {
|
|||
}
|
||||
|
||||
func generateSM4Key() []byte {
|
||||
return make([]byte, 16)
|
||||
key := make([]byte, 16)
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("生成SM4密钥失败: %v", err))
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func (c *Client) ParseNotify(rawJson string) (*NotifyRequest, error) {
|
|||
}
|
||||
|
||||
// VerifyAndParseNotify 验签并解析回调通知
|
||||
func (c *Client) VerifyAndParseNotify(rawJson string) (map[string]interface{}, error) {
|
||||
func (c *Client) VerifyAndParseNotify(rawJson string) (*YouChuOrderNotifyRequest, error) {
|
||||
var reqData map[string]string
|
||||
if err := json.Unmarshal([]byte(rawJson), &reqData); err != nil {
|
||||
return nil, fmt.Errorf("解析通知失败: %v", err)
|
||||
|
|
@ -44,10 +44,10 @@ func (c *Client) VerifyAndParseNotify(rawJson string) (map[string]interface{}, e
|
|||
return nil, fmt.Errorf("解密通知失败: %v", err)
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
var result YouChuOrderNotifyRequest
|
||||
if err := json.Unmarshal([]byte(decrypted), &result); err != nil {
|
||||
return nil, fmt.Errorf("解析解密后数据失败: %v", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return &result, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,14 +58,22 @@ func (c *Client) OrderQuery(orderNo string) (*OrderQueryResponse, error) {
|
|||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP请求失败,状态码: %d,响应: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
responseData, err := c.DecryptResponse(string(body), false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解密响应失败: %v", err)
|
||||
return nil, fmt.Errorf("解密响应失败: %v,原始响应: %s", err, string(body))
|
||||
}
|
||||
|
||||
var result OrderQueryResponse
|
||||
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v", err)
|
||||
return nil, fmt.Errorf("解析响应失败: %v,响应内容: %s", err, responseData)
|
||||
}
|
||||
|
||||
if result.RespCode != "" && result.RespCode != "0000" && result.RespCode != "00" {
|
||||
return nil, fmt.Errorf("订单查询失败,错误码: %s,错误信息: %s", result.RespCode, result.RespMsg)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
|
|
|
|||
|
|
@ -4,20 +4,26 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CreatePaymentLink 创建支付链接
|
||||
func (c *Client) CreatePaymentLink(req PaymentLinkRequest) (*PaymentLinkResponse, error) {
|
||||
payUrlTemplate := "%s&fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
var payUrlTemplate string
|
||||
if len(req.BackUrl) > 0 && strings.Contains(req.BackUrl, "?") {
|
||||
payUrlTemplate = "%s&fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
} else {
|
||||
payUrlTemplate = "%s?fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
}
|
||||
|
||||
orderData := map[string]string{
|
||||
"merchantNo": c.cfg.MchtNo,
|
||||
"orderInfos": req.ProductName,
|
||||
"orderNo": req.OrderNo,
|
||||
"amount": req.Price,
|
||||
"successUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl + req.OrderNo)),
|
||||
"successUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl)),
|
||||
"acctType": "2",
|
||||
"notifyUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl + req.OrderNo)),
|
||||
"notifyUrl": hex.EncodeToString([]byte(c.cfg.NotifyUrl)),
|
||||
}
|
||||
|
||||
signData := map[string]string{
|
||||
|
|
@ -55,10 +61,21 @@ func (c *Client) CreatePaymentLink(req PaymentLinkRequest) (*PaymentLinkResponse
|
|||
// CreatePaymentLinkWithBackUrl 创建支付链接(带 fromId 判断)
|
||||
func (c *Client) CreatePaymentLinkWithBackUrl(req PaymentLinkRequest) (*PaymentLinkResponse, error) {
|
||||
var payUrlTemplate string
|
||||
if len(req.BackUrl) > 0 && (contains(req.BackUrl, "fromId")) {
|
||||
payUrlTemplate = "%s&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
hasQuery := len(req.BackUrl) > 0 && strings.Contains(req.BackUrl, "?")
|
||||
hasFromId := len(req.BackUrl) > 0 && contains(req.BackUrl, "fromId")
|
||||
|
||||
if hasFromId {
|
||||
if hasQuery {
|
||||
payUrlTemplate = "%s&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
} else {
|
||||
payUrlTemplate = "%s?tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
}
|
||||
} else {
|
||||
payUrlTemplate = "%s&fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
if hasQuery {
|
||||
payUrlTemplate = "%s&fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
} else {
|
||||
payUrlTemplate = "%s?fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
}
|
||||
}
|
||||
|
||||
orderData := map[string]string{
|
||||
|
|
@ -66,9 +83,9 @@ func (c *Client) CreatePaymentLinkWithBackUrl(req PaymentLinkRequest) (*PaymentL
|
|||
"orderInfos": req.ProductName,
|
||||
"orderNo": req.OrderNo,
|
||||
"amount": req.Price,
|
||||
"successUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl + req.OrderNo)),
|
||||
"successUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl)),
|
||||
"acctType": "2",
|
||||
"notifyUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl + req.OrderNo)),
|
||||
"notifyUrl": hex.EncodeToString([]byte(c.cfg.NotifyUrl)),
|
||||
}
|
||||
|
||||
signData := map[string]string{
|
||||
|
|
@ -104,5 +121,5 @@ func (c *Client) CreatePaymentLinkWithBackUrl(req PaymentLinkRequest) (*PaymentL
|
|||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
return len(s) > 0 && len(substr) > 0 && (s == substr || len(s) > len(substr) && s[:len(substr)] == substr)
|
||||
return len(s) > 0 && len(substr) > 0 && strings.Contains(s, substr)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,14 +61,22 @@ func (c *Client) Refund(req RefundRequest) (*RefundResponse, error) {
|
|||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP请求失败,状态码: %d,响应: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
responseData, err := c.DecryptResponse(string(body), false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解密响应失败: %v", err)
|
||||
return nil, fmt.Errorf("解密响应失败: %v,原始响应: %s", err, string(body))
|
||||
}
|
||||
|
||||
var result RefundResponse
|
||||
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v", err)
|
||||
return nil, fmt.Errorf("解析响应失败: %v,响应内容: %s", err, responseData)
|
||||
}
|
||||
|
||||
if result.RespCode != "" && result.RespCode != "0000" && result.RespCode != "00" {
|
||||
return nil, fmt.Errorf("退款申请失败,错误码: %s,错误信息: %s", result.RespCode, result.RespMsg)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
|
|
|
|||
|
|
@ -48,10 +48,14 @@ type OrderQueryRequest struct {
|
|||
|
||||
// OrderQueryResponse 订单查询响应
|
||||
type OrderQueryResponse struct {
|
||||
OrderNo string `json:"orderNo"`
|
||||
OrderSta string `json:"orderSta"`
|
||||
RespCode string `json:"code"`
|
||||
RespMsg string `json:"respMsg"`
|
||||
RespCode string `json:"code"`
|
||||
RespMsg string `json:"respMsg"`
|
||||
RespCd string `json:"respCd"`
|
||||
ReqTraceId string `json:"reqTraceId"` //请求方流水号或者订单号,
|
||||
OrderNo string `json:"orderNo"` //统一收单订单号
|
||||
OrderSta string `json:"orderSta"` //03-支付成功 04-支付失败 05-检查失败
|
||||
TxnFg string `json:"txnFg"` //0-正常 2-已部分退货 3- 已全部退货
|
||||
TxnAmt string `json:"txnAmt"` // 交易金额 单位为元,精确到小数点后2位
|
||||
}
|
||||
|
||||
// RefundRequest 退款请求
|
||||
|
|
@ -66,8 +70,13 @@ type RefundRequest struct {
|
|||
type RefundResponse struct {
|
||||
RespCode string `json:"code"`
|
||||
RespMsg string `json:"respMsg"`
|
||||
RespCd string `json:"respCd"`
|
||||
TxnCode string `json:"txnCode"`
|
||||
SourceId string `json:"sourceId"`
|
||||
ReqTraceId string `json:"ReqTraceId"`
|
||||
RefundOrderNo string `json:"refundOrderNo"`
|
||||
RefundOrderSta string `json:"refundOrderSta"`
|
||||
MchtNo string `json:"mchtNo"`
|
||||
TxnAmt string `json:"txnAmt"`
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +112,20 @@ type NotifyResponse struct {
|
|||
LinkUrl string `json:"linkUrl"`
|
||||
}
|
||||
|
||||
type YouChuOrderNotifyRequest struct {
|
||||
TxnCode string `json:"txnCode"`
|
||||
SourceId string `json:"sourceId"`
|
||||
ReqDate string `json:"reqDate"`
|
||||
ReqTraceId string `json:"reqTraceId"` // 商户提交的订单号
|
||||
OrderNo string `json:"orderNo"` // 银行的订单号
|
||||
TxnAmt string `json:"txnAmt"`
|
||||
OrderSta string `json:"orderSta"` //03-支付成功 04-支付失败05-检查失败
|
||||
MchtNo string `json:"mchtNo"`
|
||||
TermId string `json:"termId"`
|
||||
TxnFlag string `json:"txnFlag"` //01-消费 03-退货
|
||||
TxnKind string `json:"txnKind"` //01-银行卡 02-微信 03-支付宝
|
||||
}
|
||||
|
||||
// OrderStatus 订单状态
|
||||
type OrderStatus string
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
psbc "PaymentCenter/app/third/paymentService/psbc"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"strconv"
|
||||
|
|
@ -101,17 +100,26 @@ func PsbcOrderQuery(ctx context.Context, psbcConfig PsbcPay, orderNo string) (Pa
|
|||
tradeStateDesc = "未支付"
|
||||
}
|
||||
|
||||
amountTotal := int64(0)
|
||||
payerTotal := int64(0)
|
||||
var amountTotal int64
|
||||
var payerTotal int64
|
||||
if resp.TxnAmt != "" {
|
||||
amountFloat, err := strconv.ParseFloat(resp.TxnAmt, 64)
|
||||
if err == nil {
|
||||
amountTotal = int64(amountFloat * 100)
|
||||
payerTotal = int64(amountFloat * 100)
|
||||
}
|
||||
}
|
||||
|
||||
successTime := ""
|
||||
|
||||
outTradeNo, _ := strconv.ParseInt(orderNo, 10, 64)
|
||||
return PayOrderQueryInfo{
|
||||
AppId: psbcConfig.AppID,
|
||||
OutTradeNo: outTradeNo,
|
||||
TransactionId: "",
|
||||
TransactionId: resp.OrderNo,
|
||||
TradeState: tradeState,
|
||||
TradeStateDesc: tradeStateDesc,
|
||||
SuccessTime: "",
|
||||
SuccessTime: successTime,
|
||||
AmountTotal: amountTotal,
|
||||
PayerTotal: payerTotal,
|
||||
}, nil
|
||||
|
|
@ -177,26 +185,14 @@ func PsbcVerifyAndParseNotify(rawBody string, psbcConfig PsbcPay) (orderId int64
|
|||
return 0, 0, 0, "", err
|
||||
}
|
||||
|
||||
orderNoStr := ""
|
||||
if orderNo, ok := result["orderNo"].(string); ok {
|
||||
orderNoStr = orderNo
|
||||
}
|
||||
if orderNoStr == "" {
|
||||
return 0, 0, 0, "", errors.New("回调数据中缺少订单号")
|
||||
}
|
||||
|
||||
orderId, err = strconv.ParseInt(orderNoStr, 10, 64)
|
||||
orderId, err = strconv.ParseInt(result.ReqTraceId, 10, 64)
|
||||
if err != nil {
|
||||
logger.Error(context.Background(), "PsbcVerifyAndParseNotify 发生错误", fmt.Sprintf("订单号转换失败,错误信息:%s", err.Error()))
|
||||
return 0, 0, 0, "", err
|
||||
}
|
||||
|
||||
amountStr := ""
|
||||
if amount, ok := result["amount"].(string); ok {
|
||||
amountStr = amount
|
||||
}
|
||||
if amountStr != "" {
|
||||
amountFloat, err := strconv.ParseFloat(amountStr, 64)
|
||||
if result.TxnAmt != "" {
|
||||
amountFloat, err := strconv.ParseFloat(result.TxnAmt, 64)
|
||||
if err == nil {
|
||||
amountTotal = int64(amountFloat * 100)
|
||||
payerTotal = amountTotal
|
||||
|
|
@ -204,8 +200,8 @@ func PsbcVerifyAndParseNotify(rawBody string, psbcConfig PsbcPay) (orderId int64
|
|||
}
|
||||
|
||||
orderSta := ""
|
||||
if sta, ok := result["orderSta"].(string); ok {
|
||||
orderSta = sta
|
||||
if result.OrderSta != "" {
|
||||
orderSta = result.OrderSta
|
||||
}
|
||||
|
||||
switch orderSta {
|
||||
|
|
|
|||
Loading…
Reference in New Issue