You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
3.3 KiB
Go

package wechat
import (
"cls/internal/domain/payment"
"cls/pkg/logger"
"crypto/md5"
"encoding/hex"
"encoding/xml"
"fmt"
"sort"
"strings"
)
// Config 微信支付配置
type Config struct {
AppID string // 公众号ID
MchID string // 商户号
APIKey string // API密钥
NotifyURL string // 支付回调通知地址
}
// Service 微信支付服务
type Service struct {
config Config
client *APIClient
log logger.Logger
}
// NewService 创建微信支付服务
func NewService(config Config, log logger.New) *Service {
return &Service{
config: config,
client: NewAPIClient(config),
log: log("cls:payment:wechat"),
}
}
// CreatePayment 创建支付订单
func (s *Service) CreatePayment(order *payment.Payment) (map[string]interface{}, error) {
// 构建统一下单请求
req := &UnifiedOrderRequest{
Body: order.Description,
OutTradeNo: order.OrderNo,
TotalFee: fmt.Sprintf("%d", order.Amount),
}
// 调用统一下单接口
resp, err := s.client.UnifiedOrder(req)
if err != nil {
return nil, fmt.Errorf("创建支付订单失败: %v", err)
}
// 检查响应结果
if resp.ReturnCode != "SUCCESS" {
return nil, fmt.Errorf("微信支付接口返回错误: %s", resp.ReturnMsg)
}
if resp.ResultCode != "SUCCESS" {
return nil, fmt.Errorf("微信支付业务处理失败: %s", resp.ErrCodeDes)
}
// 返回支付二维码链接
return map[string]interface{}{
"code_url": resp.CodeURL,
}, nil
}
// VerifyNotify 验证支付回调通知
func (s *Service) VerifyNotify(notifyData string) (map[string]string, error) {
// 解析XML数据
var notify struct {
ReturnCode string `xml:"return_code"`
ReturnMsg string `xml:"return_msg"`
ResultCode string `xml:"result_code"`
ErrCode string `xml:"err_code"`
ErrCodeDes string `xml:"err_code_des"`
OutTradeNo string `xml:"out_trade_no"`
TotalFee string `xml:"total_fee"`
TransactionID string `xml:"transaction_id"`
Sign string `xml:"sign"`
}
if err := xml.Unmarshal([]byte(notifyData), &notify); err != nil {
return nil, fmt.Errorf("解析通知数据失败: %v", err)
}
// 验证签名
if !s.client.verifySign(&notify) {
return nil, fmt.Errorf("签名验证失败")
}
// 检查支付结果
if notify.ReturnCode != "SUCCESS" || notify.ResultCode != "SUCCESS" {
return nil, fmt.Errorf("支付失败: %s", notify.ErrCodeDes)
}
return map[string]string{
"order_no": notify.OutTradeNo,
"amount": notify.TotalFee,
"transaction_id": notify.TransactionID,
}, nil
}
// generateSign 生成签名
func (s *Service) generateSign(params map[string]string) string {
// 按键排序
var keys []string
for k := range params {
if k != "sign" && params[k] != "" {
keys = append(keys, k)
}
}
sort.Strings(keys)
// 拼接字符串
var builder strings.Builder
for i, k := range keys {
if i > 0 {
builder.WriteString("&")
}
builder.WriteString(k)
builder.WriteString("=")
builder.WriteString(params[k])
}
builder.WriteString("&key=")
builder.WriteString(s.config.APIKey)
// MD5加密
h := md5.New()
h.Write([]byte(builder.String()))
return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}
// verifySign 验证签名
func (s *Service) verifySign(notifyData, sign string) bool {
// TODO: 实现签名验证逻辑
return true
}