218 lines
7.3 KiB
Go
218 lines
7.3 KiB
Go
package wechat
|
||
|
||
import (
|
||
"context"
|
||
"crypto/tls"
|
||
"encoding/xml"
|
||
"errors"
|
||
"fmt"
|
||
|
||
"github.com/go-pay/gopay"
|
||
"github.com/go-pay/gopay/pkg/util"
|
||
)
|
||
|
||
// 统一下单
|
||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
|
||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=9_1
|
||
func (w *Client) UnifiedOrder(ctx context.Context, bm gopay.BodyMap) (wxRsp *UnifiedOrderResponse, err error) {
|
||
err = bm.CheckEmptyError("nonce_str", "body", "out_trade_no", "total_fee", "spbill_create_ip", "notify_url", "trade_type")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var bs []byte
|
||
if w.IsProd {
|
||
bs, err = w.doProdPost(ctx, bm, unifiedOrder, nil)
|
||
} else {
|
||
bm.Set("total_fee", 101)
|
||
bs, err = w.doSanBoxPost(ctx, bm, sandboxUnifiedOrder)
|
||
}
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
wxRsp = new(UnifiedOrderResponse)
|
||
if err = xml.Unmarshal(bs, wxRsp); err != nil {
|
||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||
}
|
||
return wxRsp, nil
|
||
}
|
||
|
||
// 提交付款码支付
|
||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
|
||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/api/micropay_sl.php?chapter=9_10&index=1
|
||
func (w *Client) Micropay(ctx context.Context, bm gopay.BodyMap) (wxRsp *MicropayResponse, err error) {
|
||
err = bm.CheckEmptyError("nonce_str", "body", "out_trade_no", "total_fee", "spbill_create_ip", "auth_code")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var bs []byte
|
||
if w.IsProd {
|
||
bs, err = w.doProdPost(ctx, bm, microPay, nil)
|
||
} else {
|
||
bm.Set("total_fee", 1)
|
||
bs, err = w.doSanBoxPost(ctx, bm, sandboxMicroPay)
|
||
}
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
wxRsp = new(MicropayResponse)
|
||
if err = xml.Unmarshal(bs, wxRsp); err != nil {
|
||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||
}
|
||
return wxRsp, nil
|
||
}
|
||
|
||
// 查询订单
|
||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2
|
||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=9_2
|
||
func (w *Client) QueryOrder(ctx context.Context, bm gopay.BodyMap) (wxRsp *QueryOrderResponse, resBm gopay.BodyMap, err error) {
|
||
err = bm.CheckEmptyError("nonce_str")
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
if bm.GetString("out_trade_no") == util.NULL && bm.GetString("transaction_id") == util.NULL {
|
||
return nil, nil, errors.New("out_trade_no and transaction_id are not allowed to be null at the same time")
|
||
}
|
||
var bs []byte
|
||
if w.IsProd {
|
||
bs, err = w.doProdPost(ctx, bm, orderQuery, nil)
|
||
} else {
|
||
bs, err = w.doSanBoxPost(ctx, bm, sandboxOrderQuery)
|
||
}
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
wxRsp = new(QueryOrderResponse)
|
||
if err = xml.Unmarshal(bs, wxRsp); err != nil {
|
||
return nil, nil, fmt.Errorf("xml.UnmarshalStruct(%s):%w", string(bs), err)
|
||
}
|
||
resBm = make(gopay.BodyMap)
|
||
if err = xml.Unmarshal(bs, &resBm); err != nil {
|
||
return nil, nil, fmt.Errorf("xml.UnmarshalBodyMap(%s):%w", string(bs), err)
|
||
}
|
||
return wxRsp, resBm, nil
|
||
}
|
||
|
||
// 关闭订单
|
||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3
|
||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=9_3
|
||
func (w *Client) CloseOrder(ctx context.Context, bm gopay.BodyMap) (wxRsp *CloseOrderResponse, err error) {
|
||
err = bm.CheckEmptyError("nonce_str", "out_trade_no")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var bs []byte
|
||
if w.IsProd {
|
||
bs, err = w.doProdPost(ctx, bm, closeOrder, nil)
|
||
} else {
|
||
bs, err = w.doSanBoxPost(ctx, bm, sandboxCloseOrder)
|
||
}
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
wxRsp = new(CloseOrderResponse)
|
||
if err = xml.Unmarshal(bs, wxRsp); err != nil {
|
||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||
}
|
||
return wxRsp, nil
|
||
}
|
||
|
||
// 申请退款
|
||
// 注意:请在初始化client时,调用 client 添加证书的相关方法添加证书
|
||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
|
||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=9_4
|
||
func (w *Client) Refund(ctx context.Context, bm gopay.BodyMap) (wxRsp *RefundResponse, resBm gopay.BodyMap, err error) {
|
||
err = bm.CheckEmptyError("nonce_str", "out_refund_no", "total_fee", "refund_fee")
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
if bm.GetString("out_trade_no") == util.NULL && bm.GetString("transaction_id") == util.NULL {
|
||
return nil, nil, errors.New("out_trade_no and transaction_id are not allowed to be null at the same time")
|
||
}
|
||
var (
|
||
bs []byte
|
||
tlsConfig *tls.Config
|
||
)
|
||
if w.IsProd {
|
||
if tlsConfig, err = w.addCertConfig(nil, nil, nil); err != nil {
|
||
return nil, nil, err
|
||
}
|
||
bs, err = w.doProdPost(ctx, bm, refund, tlsConfig)
|
||
} else {
|
||
bs, err = w.doSanBoxPost(ctx, bm, sandboxRefund)
|
||
}
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
wxRsp = new(RefundResponse)
|
||
if err = xml.Unmarshal(bs, wxRsp); err != nil {
|
||
return nil, nil, fmt.Errorf("xml.UnmarshalStruct(%s):%w", string(bs), err)
|
||
}
|
||
resBm = make(gopay.BodyMap)
|
||
if err = xml.Unmarshal(bs, &resBm); err != nil {
|
||
return nil, nil, fmt.Errorf("xml.UnmarshalBodyMap(%s):%w", string(bs), err)
|
||
}
|
||
return wxRsp, resBm, nil
|
||
}
|
||
|
||
// 查询退款
|
||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
|
||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=9_5
|
||
func (w *Client) QueryRefund(ctx context.Context, bm gopay.BodyMap) (wxRsp *QueryRefundResponse, resBm gopay.BodyMap, err error) {
|
||
err = bm.CheckEmptyError("nonce_str")
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
if bm.GetString("refund_id") == util.NULL && bm.GetString("out_refund_no") == util.NULL && bm.GetString("transaction_id") == util.NULL && bm.GetString("out_trade_no") == util.NULL {
|
||
return nil, nil, errors.New("refund_id, out_refund_no, out_trade_no, transaction_id are not allowed to be null at the same time")
|
||
}
|
||
var bs []byte
|
||
if w.IsProd {
|
||
bs, err = w.doProdPost(ctx, bm, refundQuery, nil)
|
||
} else {
|
||
bs, err = w.doSanBoxPost(ctx, bm, sandboxRefundQuery)
|
||
}
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
wxRsp = new(QueryRefundResponse)
|
||
if err = xml.Unmarshal(bs, wxRsp); err != nil {
|
||
return nil, nil, fmt.Errorf("xml.UnmarshalStruct(%s):%w", string(bs), err)
|
||
}
|
||
resBm = make(gopay.BodyMap)
|
||
if err = xml.Unmarshal(bs, &resBm); err != nil {
|
||
return nil, nil, fmt.Errorf("xml.UnmarshalBodyMap(%s):%w", string(bs), err)
|
||
}
|
||
return wxRsp, resBm, nil
|
||
}
|
||
|
||
// 撤销订单
|
||
// 注意:请在初始化client时,调用 client 添加证书的相关方法添加证书
|
||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
|
||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/api/micropay_sl.php?chapter=9_11&index=3
|
||
func (w *Client) Reverse(ctx context.Context, bm gopay.BodyMap) (wxRsp *ReverseResponse, err error) {
|
||
err = bm.CheckEmptyError("nonce_str", "out_trade_no")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var (
|
||
bs []byte
|
||
tlsConfig *tls.Config
|
||
)
|
||
if w.IsProd {
|
||
if tlsConfig, err = w.addCertConfig(nil, nil, nil); err != nil {
|
||
return nil, err
|
||
}
|
||
bs, err = w.doProdPost(ctx, bm, reverse, tlsConfig)
|
||
} else {
|
||
bs, err = w.doSanBoxPost(ctx, bm, sandboxReverse)
|
||
}
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
wxRsp = new(ReverseResponse)
|
||
if err = xml.Unmarshal(bs, wxRsp); err != nil {
|
||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||
}
|
||
return wxRsp, nil
|
||
}
|