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) }