139 lines
4.0 KiB
Go
139 lines
4.0 KiB
Go
package wechat
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"soul-api/internal/config"
|
||
|
||
"github.com/ArtisanCloud/PowerLibs/v3/object"
|
||
"github.com/ArtisanCloud/PowerWeChat/v3/src/payment/transfer/request"
|
||
)
|
||
|
||
// TransferParams 转账参数
|
||
type TransferParams struct {
|
||
OutBatchNo string // 商家批次单号(唯一)
|
||
OutDetailNo string // 商家明细单号(唯一)
|
||
OpenID string // 收款用户 openid
|
||
Amount int // 转账金额(分)
|
||
UserName string // 收款用户姓名(可选,用于实名校验)
|
||
Remark string // 转账备注
|
||
BatchName string // 批次名称(如"提现")
|
||
BatchRemark string // 批次备注
|
||
}
|
||
|
||
// TransferResult 转账结果
|
||
type TransferResult struct {
|
||
BatchID string // 微信批次单号
|
||
OutBatchNo string // 商家批次单号
|
||
CreateTime time.Time // 批次创建时间
|
||
BatchStatus string // 批次状态:ACCEPTED-已受理 等
|
||
}
|
||
|
||
// InitTransfer 保留兼容:转账已由 Init() 中 PowerWeChat Payment 统一初始化,调用无副作用
|
||
func InitTransfer(_ *config.Config) error {
|
||
return nil
|
||
}
|
||
|
||
// InitiateTransfer 发起商家转账到零钱(PowerWeChat TransferBatch)
|
||
func InitiateTransfer(params TransferParams) (*TransferResult, error) {
|
||
if paymentApp == nil {
|
||
return nil, fmt.Errorf("支付/转账未初始化,请先调用 wechat.Init")
|
||
}
|
||
|
||
detail := &request.TransferDetail{
|
||
OutDetailNO: params.OutDetailNo,
|
||
TransferAmount: params.Amount,
|
||
TransferRemark: params.Remark,
|
||
OpenID: params.OpenID,
|
||
}
|
||
if params.UserName != "" {
|
||
detail.UserName = object.NewNullString(params.UserName, true)
|
||
}
|
||
req := &request.RequestTransferBatch{
|
||
AppID: cfg.WechatAppID,
|
||
OutBatchNO: params.OutBatchNo,
|
||
BatchName: params.BatchName,
|
||
BatchRemark: params.BatchRemark,
|
||
TotalAmount: params.Amount,
|
||
TotalNum: 1,
|
||
TransferDetailList: []*request.TransferDetail{detail},
|
||
}
|
||
if cfg.WechatTransferURL != "" {
|
||
req.SetNotifyUrl(cfg.WechatTransferURL)
|
||
}
|
||
|
||
resp, err := paymentApp.TransferBatch.Batch(context.Background(), req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("发起转账失败: %w", err)
|
||
}
|
||
if resp == nil {
|
||
return nil, fmt.Errorf("转账返回为空")
|
||
}
|
||
|
||
result := &TransferResult{
|
||
OutBatchNo: resp.OutBatchNo,
|
||
BatchStatus: "ACCEPTED",
|
||
}
|
||
if resp.BatchId != "" {
|
||
result.BatchID = resp.BatchId
|
||
}
|
||
if !resp.CreateTime.IsZero() {
|
||
result.CreateTime = resp.CreateTime
|
||
}
|
||
return result, nil
|
||
}
|
||
|
||
// QueryTransfer 查询转账结果(可选,转账状态也可通过回调获取)
|
||
func QueryTransfer(outBatchNo, outDetailNo string) (map[string]interface{}, error) {
|
||
if paymentApp == nil {
|
||
return map[string]interface{}{
|
||
"out_batch_no": outBatchNo,
|
||
"out_detail_no": outDetailNo,
|
||
"status": "unknown",
|
||
"message": "转账未初始化",
|
||
}, nil
|
||
}
|
||
detail, err := paymentApp.TransferBatch.QueryOutBatchNoDetail(context.Background(), outBatchNo, outDetailNo)
|
||
if err != nil {
|
||
return map[string]interface{}{
|
||
"out_batch_no": outBatchNo,
|
||
"out_detail_no": outDetailNo,
|
||
"status": "processing",
|
||
"message": err.Error(),
|
||
}, nil
|
||
}
|
||
if detail == nil {
|
||
return map[string]interface{}{
|
||
"out_batch_no": outBatchNo,
|
||
"out_detail_no": outDetailNo,
|
||
"status": "processing",
|
||
"message": "转账处理中",
|
||
}, nil
|
||
}
|
||
return map[string]interface{}{
|
||
"out_batch_no": outBatchNo,
|
||
"out_detail_no": outDetailNo,
|
||
"detail_status": detail.DetailStatus,
|
||
"fail_reason": detail.FailReason,
|
||
"transfer_amount": detail.TransferAmount,
|
||
}, nil
|
||
}
|
||
|
||
// GenerateTransferBatchNo 生成转账批次单号
|
||
func GenerateTransferBatchNo() string {
|
||
now := time.Now()
|
||
timestamp := now.Format("20060102150405")
|
||
random := now.UnixNano() % 1000000
|
||
return fmt.Sprintf("WD%s%06d", timestamp, random)
|
||
}
|
||
|
||
// GenerateTransferDetailNo 生成转账明细单号
|
||
func GenerateTransferDetailNo() string {
|
||
now := time.Now()
|
||
timestamp := now.Format("20060102150405")
|
||
random := now.UnixNano() % 1000000
|
||
return fmt.Sprintf("WDD%s%06d", timestamp, random)
|
||
}
|