103 lines
2.4 KiB
Go
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
|
|
}
|