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 }