Files
lone-services/pkg/wechat/pay/refund.go
T
2026-09-11 16:08:17 +08:00

103 lines
2.4 KiB
Go

package pay
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
const domesticRefundPath = "/v3/refund/domestic/refunds"
func (c *Client) Refund(ctx context.Context, req *RefundRequest) (*RefundResponse, error) {
if req == nil {
return nil, fmt.Errorf("request is required")
}
if req.OutTradeNo == "" && req.TransactionID == "" {
return nil, fmt.Errorf("out_trade_no or transaction_id is required")
}
if req.OutRefundNo == "" {
return nil, fmt.Errorf("out_refund_no is required")
}
if req.Amount.Refund <= 0 {
return nil, fmt.Errorf("amount.refund must be greater than 0")
}
if req.Amount.Total <= 0 {
return nil, fmt.Errorf("amount.total must be greater than 0")
}
if req.Amount.Refund > req.Amount.Total {
return nil, fmt.Errorf("amount.refund cannot be greater than amount.total")
}
currency := req.Amount.Currency
if currency == "" {
currency = "CNY"
}
body := RefundRequest{
OutTradeNo: req.OutTradeNo,
TransactionID: req.TransactionID,
OutRefundNo: req.OutRefundNo,
Reason: req.Reason,
NotifyURL: req.NotifyURL,
Amount: RefundAmount{
Refund: req.Amount.Refund,
Total: req.Amount.Total,
Currency: currency,
},
}
reqBody, err := json.Marshal(body)
if err != nil {
return nil, err
}
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.Host+domesticRefundPath, bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Content-Type", "application/json")
if c.platformSerial != "" {
httpReq.Header.Set("Wechatpay-Serial", c.platformSerial)
}
authorization, err := c.buildAuthorization(http.MethodPost, domesticRefundPath, reqBody)
if err != nil {
return nil, err
}
httpReq.Header.Set("Authorization", authorization)
resp, err := c.httpClient.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if !isSuccessStatus(resp.StatusCode) {
return nil, newAPIError(resp.StatusCode, respBody)
}
if err := c.validateResponse(resp.Header, respBody); err != nil {
return nil, err
}
var result RefundResponse
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, err
}
if result.RefundID == "" {
return nil, fmt.Errorf("empty refund_id in response")
}
return &result, nil
}