增加vendor
This commit is contained in:
+146
@@ -0,0 +1,146 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 提交申请单API
|
||||
// 注意:本接口会提交一些敏感信息,需调用 client.V3EncryptText() 进行加密
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter11_1_1.shtml
|
||||
func (c *ClientV3) V3Apply4SubSubmit(ctx context.Context, bm gopay.BodyMap) (*Apply4SubSubmitRsp, error) {
|
||||
if err := bm.CheckEmptyError("business_code", "contact_info", "subject_info", "business_info", "settlement_info", "bank_account_info"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3Apply4SubSubmit, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3Apply4SubSubmit, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &Apply4SubSubmitRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Apply4SubSubmit)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 通过业务申请编号查询申请状态API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter11_1_2.shtml
|
||||
func (c *ClientV3) V3Apply4SubQueryByBusinessCode(ctx context.Context, businessCode string) (*Apply4SubQueryRsp, error) {
|
||||
uri := fmt.Sprintf(v3Apply4SubQueryByBusinessCode, businessCode)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &Apply4SubQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Apply4SubQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 通过申请单号查询申请状态API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter11_1_2.shtml
|
||||
func (c *ClientV3) V3Apply4SubQueryByApplyId(ctx context.Context, applyId string) (*Apply4SubQueryRsp, error) {
|
||||
uri := fmt.Sprintf(v3Apply4SubQueryByApplyId, applyId)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &Apply4SubQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Apply4SubQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 修改结算账号 API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter11_1_3.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_4.shtml
|
||||
func (c *ClientV3) V3Apply4SubModifySettlement(ctx context.Context, bm gopay.BodyMap) (*EmptyRsp, error) {
|
||||
if err := bm.CheckEmptyError("sub_mchid", "account_type", "account_bank", "account_number"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postUrl := fmt.Sprintf(v3Apply4SubModifySettlement, bm["sub_mchid"])
|
||||
bm.Remove("sub_mchid")
|
||||
authorization, err := c.authorization(MethodPost, postUrl, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, postUrl, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询结算账户 API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter11_1_4.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_5.shtml
|
||||
func (c *ClientV3) V3Apply4SubQuerySettlement(ctx context.Context, subMchId string) (*Apply4SubQuerySettlementRsp, error) {
|
||||
uri := fmt.Sprintf(v3Apply4SubQuerySettlement, subMchId)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &Apply4SubQuerySettlementRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Apply4SubQuerySettlement)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// 获取对私银行卡号开户银行
|
||||
// 注意:accountNo 需此方法加密:client.V3EncryptText()
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_1.shtml
|
||||
func (c *ClientV3) V3BankSearchBank(ctx context.Context, accountNo string) (wxRsp *BankSearchBankRsp, err error) {
|
||||
uri := v3BankSearchBank + "?account_number=" + url.QueryEscape(accountNo)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BankSearchBankRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BankSearchBank)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询支持个人业务的银行列表
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_2.shtml
|
||||
func (c *ClientV3) V3BankSearchPersonalList(ctx context.Context, limit, offset int) (wxRsp *BankSearchPersonalListRsp, err error) {
|
||||
if limit == 0 {
|
||||
limit = 20
|
||||
}
|
||||
uri := v3BankSearchPersonalList + "?limit=" + util.Int2String(limit) + "&offset=" + util.Int2String(offset)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BankSearchPersonalListRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BankSearchList)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询支持对公业务的银行列表
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_3.shtml
|
||||
func (c *ClientV3) V3BankSearchCorporateList(ctx context.Context, limit, offset int) (wxRsp *BankSearchCorporateListRsp, err error) {
|
||||
if limit == 0 {
|
||||
limit = 20
|
||||
}
|
||||
uri := v3BankSearchCorporateList + "?limit=" + util.Int2String(limit) + "&offset=" + util.Int2String(offset)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BankSearchCorporateListRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BankSearchList)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询省份列表
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_4.shtml
|
||||
func (c *ClientV3) V3BankSearchProvinceList(ctx context.Context) (wxRsp *BankSearchProvinceListRsp, err error) {
|
||||
authorization, err := c.authorization(MethodGet, v3BankSearchProvinceList, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, v3BankSearchProvinceList, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BankSearchProvinceListRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BankSearchProvince)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询城市列表
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_5.shtml
|
||||
func (c *ClientV3) V3BankSearchCityList(ctx context.Context, provinceCode int) (wxRsp *BankSearchCityListRsp, err error) {
|
||||
url := fmt.Sprintf(v3BankSearchCityList, provinceCode)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BankSearchCityListRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BankSearchCity)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询支行列表
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter11_2_6.shtml
|
||||
func (c *ClientV3) V3BankSearchBranchList(ctx context.Context, bankAliasCode string, cityCode, limit, offset int) (wxRsp *BankSearchBranchListRsp, err error) {
|
||||
if limit == 0 {
|
||||
limit = 20
|
||||
}
|
||||
uri := fmt.Sprintf(v3BankSearchBranchList, bankAliasCode) + "?city_code=" + util.Int2String(cityCode) + "&limit=" + util.Int2String(limit) + "&offset=" + util.Int2String(offset)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BankSearchBranchListRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BankSearchBranch)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// 申请交易账单API
|
||||
// 注意:如 bill_date 为空,默认查前一天的
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_6.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_6.shtml
|
||||
func (c *ClientV3) V3BillTradeBill(ctx context.Context, bm gopay.BodyMap) (wxRsp *BillRsp, err error) {
|
||||
if bm != nil {
|
||||
if bm.GetString("bill_date") == util.NULL {
|
||||
now := time.Now()
|
||||
yesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local).Format(util.DateLayout)
|
||||
bm.Set("bill_date", yesterday)
|
||||
}
|
||||
}
|
||||
uri := v3TradeBill + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &BillRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TradeBill)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 申请资金账单API
|
||||
// 注意:如 bill_date 为空,默认查前一天的
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_7.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_7.shtml
|
||||
func (c *ClientV3) V3BillFundFlowBill(ctx context.Context, bm gopay.BodyMap) (wxRsp *BillRsp, err error) {
|
||||
if bm != nil {
|
||||
if bm.GetString("bill_date") == util.NULL {
|
||||
now := time.Now()
|
||||
yesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local).Format(util.DateLayout)
|
||||
bm.Set("bill_date", yesterday)
|
||||
}
|
||||
}
|
||||
uri := v3FundFlowBill + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &BillRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TradeBill)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 申请特约商户资金账单API
|
||||
// 注意:如 bill_date 为空,默认查前一天的
|
||||
// Code = 0 is success
|
||||
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter7_2.shtml
|
||||
func (c *ClientV3) V3BillEcommerceFundFlowBill(ctx context.Context, bm gopay.BodyMap) (wxRsp *EcommerceFundFlowBillRsp, err error) {
|
||||
if bm != nil {
|
||||
if bm.GetString("bill_date") == util.NULL {
|
||||
now := time.Now()
|
||||
yesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local).Format(util.DateLayout)
|
||||
bm.Set("bill_date", yesterday)
|
||||
}
|
||||
if bm.GetString("account_type") == util.NULL {
|
||||
bm.Set("account_type", "ALL")
|
||||
}
|
||||
if bm.GetString("algorithm") == util.NULL {
|
||||
bm.Set("algorithm", "AEAD_AES_256_GCM")
|
||||
}
|
||||
}
|
||||
uri := v3EcommerceFundFlowBill + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &EcommerceFundFlowBillRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(DownloadBill)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 申请单个子商户资金账单API
|
||||
// 注意:如 bill_date 为空,默认查前一天的
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_12.shtml
|
||||
func (c *ClientV3) V3BillSubFundFlowBill(ctx context.Context, bm gopay.BodyMap) (wxRsp *BillRsp, err error) {
|
||||
if bm != nil {
|
||||
if bm.GetString("bill_date") == util.NULL {
|
||||
now := time.Now()
|
||||
yesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local).Format(util.DateLayout)
|
||||
bm.Set("bill_date", yesterday)
|
||||
}
|
||||
}
|
||||
uri := v3SubFundFlowBill + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &BillRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TradeBill)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 下载账单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_8.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_8.shtml
|
||||
func (c *ClientV3) V3BillDownLoadBill(ctx context.Context, downloadUrl string) (fileBytes []byte, err error) {
|
||||
if downloadUrl == gopay.NULL {
|
||||
return nil, errors.New("invalid download url")
|
||||
}
|
||||
split := strings.Split(downloadUrl, ".com")
|
||||
if len(split) != 2 {
|
||||
return nil, errors.New("invalid download url")
|
||||
}
|
||||
authorization, err := c.authorization(MethodGet, split[1], nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, _, bs, err := c.doProdGet(ctx, split[1], authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(string(bs))
|
||||
}
|
||||
return bs, nil
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 商圈积分同步
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_6_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_6_2.shtml
|
||||
func (c *ClientV3) V3BusinessPointsSync(ctx context.Context, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusinessPointsSync, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusinessPointsSync, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商圈积分授权查询
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_6_4.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_6_4.shtml
|
||||
func (c *ClientV3) V3BusinessAuthPointsQuery(ctx context.Context, appid, openid string) (*BusinessAuthPointsQueryRsp, error) {
|
||||
uri := fmt.Sprintf(v3BusinessAuthPointsQuery, openid) + "?appid=" + appid
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &BusinessAuthPointsQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusinessAuthPointsQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/aes"
|
||||
"github.com/go-pay/gopay/pkg/errgroup"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
"github.com/go-pay/gopay/pkg/xhttp"
|
||||
"github.com/go-pay/gopay/pkg/xlog"
|
||||
"github.com/go-pay/gopay/pkg/xpem"
|
||||
"github.com/go-pay/gopay/pkg/xtime"
|
||||
)
|
||||
|
||||
// 获取微信平台证书公钥(获取后自行保存使用,如需定期刷新功能,自行实现)
|
||||
// 注意事项
|
||||
// 如果自行实现验证平台签名逻辑的话,需要注意以下事项:
|
||||
// - 程序实现定期更新平台证书的逻辑,不要硬编码验证应答消息签名的平台证书
|
||||
// - 定期调用该接口,间隔时间小于12小时
|
||||
// - 加密请求消息中的敏感信息时,使用最新的平台证书(即:证书启用时间较晚的证书)
|
||||
// 文档说明:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay5_1.shtml
|
||||
func GetPlatformCerts(ctx context.Context, mchid, apiV3Key, serialNo, privateKey string) (certs *PlatformCertRsp, err error) {
|
||||
var (
|
||||
eg = new(errgroup.Group)
|
||||
mu sync.Mutex
|
||||
jb = ""
|
||||
)
|
||||
// Prepare
|
||||
priKey, err := xpem.DecodePrivateKey([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
nonceStr := util.RandomString(32)
|
||||
ts := util.Int642String(timestamp)
|
||||
_str := MethodGet + "\n" + v3GetCerts + "\n" + ts + "\n" + nonceStr + "\n" + jb + "\n"
|
||||
// Sign
|
||||
h := sha256.New()
|
||||
h.Write([]byte(_str))
|
||||
result, err := rsa.SignPKCS1v15(rand.Reader, priKey, crypto.SHA256, h.Sum(nil))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %+v", gopay.SignatureErr, err)
|
||||
}
|
||||
sign := base64.StdEncoding.EncodeToString(result)
|
||||
// Authorization
|
||||
authorization := Authorization + ` mchid="` + mchid + `",nonce_str="` + nonceStr + `",timestamp="` + ts + `",serial_no="` + serialNo + `",signature="` + sign + `"`
|
||||
// Request
|
||||
var url = v3BaseUrlCh + v3GetCerts
|
||||
httpClient := xhttp.NewClient()
|
||||
httpClient.Header.Add(HeaderAuthorization, authorization)
|
||||
httpClient.Header.Add(HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
|
||||
httpClient.Header.Add(HeaderSerial, serialNo)
|
||||
httpClient.Header.Add("Accept", "*/*")
|
||||
res, bs, err := httpClient.Type(xhttp.TypeJSON).Get(url).EndBytes(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs = &PlatformCertRsp{Code: Success}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
certs.Code = res.StatusCode
|
||||
certs.Error = string(bs)
|
||||
return certs, nil
|
||||
}
|
||||
// Parse
|
||||
certRsp := new(PlatformCert)
|
||||
if err = json.Unmarshal(bs, certRsp); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s):%+v", string(bs), err)
|
||||
}
|
||||
for _, v := range certRsp.Data {
|
||||
cert := v
|
||||
if cert.EncryptCertificate != nil {
|
||||
ec := cert.EncryptCertificate
|
||||
eg.Go(func(ctx context.Context) error {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ec.Ciphertext)
|
||||
pubKeyBytes, err := aes.GCMDecrypt(cipherBytes, []byte(ec.Nonce), []byte(ec.AssociatedData), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return fmt.Errorf("aes.GCMDecrypt, err:%+v", err)
|
||||
}
|
||||
pci := &PlatformCertItem{
|
||||
EffectiveTime: cert.EffectiveTime,
|
||||
ExpireTime: cert.ExpireTime,
|
||||
PublicKey: string(pubKeyBytes),
|
||||
SerialNo: cert.SerialNo,
|
||||
}
|
||||
mu.Lock()
|
||||
certs.Certs = append(certs.Certs, pci)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
if err = eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return certs, nil
|
||||
}
|
||||
|
||||
// 设置 微信支付平台证书 和 证书序列号
|
||||
// 注意1:如已开启自动验签功能 client.AutoVerifySign(),无需再调用此方法设置
|
||||
// 注意2:请预先通过 wechat.GetPlatformCerts() 获取 微信平台公钥证书 和 证书序列号
|
||||
// 部分接口请求参数中敏感信息加密,使用此 微信支付平台公钥 和 证书序列号
|
||||
func (c *ClientV3) SetPlatformCert(wxPublicKeyContent []byte, wxSerialNo string) (client *ClientV3) {
|
||||
pubKey, err := xpem.DecodePublicKey(wxPublicKeyContent)
|
||||
if err != nil {
|
||||
xlog.Errorf("SetPlatformCert(%s),err:%+v", wxPublicKeyContent, err)
|
||||
}
|
||||
if pubKey != nil {
|
||||
c.wxPublicKey = pubKey
|
||||
}
|
||||
c.WxSerialNo = wxSerialNo
|
||||
return c
|
||||
}
|
||||
|
||||
// 获取 微信平台证书(readonly)
|
||||
func (c *ClientV3) WxPublicKey() (wxPublicKey *rsa.PublicKey) {
|
||||
wxPublicKey = c.wxPublicKey
|
||||
return
|
||||
}
|
||||
|
||||
// 获取并选择最新的有效证书
|
||||
func (c *ClientV3) GetAndSelectNewestCert() (cert, serialNo string, err error) {
|
||||
certs, err := c.getPlatformCerts()
|
||||
if err != nil {
|
||||
return gopay.NULL, gopay.NULL, err
|
||||
}
|
||||
if certs.Code == Success && len(certs.Certs) > 0 {
|
||||
// only one
|
||||
if len(certs.Certs) == 1 {
|
||||
formatExpire := xtime.FormatDateTime(certs.Certs[0].ExpireTime)
|
||||
expireTime, err := time.ParseInLocation(xtime.TimeLayout, formatExpire, time.Local)
|
||||
if err != nil {
|
||||
return gopay.NULL, gopay.NULL, fmt.Errorf("time.ParseInLocation(%s, %s),err:%w", xtime.TimeLayout, formatExpire, err)
|
||||
}
|
||||
if time.Now().Unix() >= expireTime.Unix() {
|
||||
// 过期了
|
||||
return gopay.NULL, gopay.NULL, fmt.Errorf("wechat platform API cert expired, expired time: %s", formatExpire)
|
||||
}
|
||||
return certs.Certs[0].PublicKey, certs.Certs[0].SerialNo, nil
|
||||
}
|
||||
// more one
|
||||
var (
|
||||
effectiveTs []int
|
||||
certMap = make(map[int]*PlatformCertItem)
|
||||
)
|
||||
for _, v := range certs.Certs {
|
||||
formatEffective := xtime.FormatDateTime(v.EffectiveTime)
|
||||
effectiveTime, err := time.ParseInLocation(xtime.TimeLayout, formatEffective, time.Local)
|
||||
if err != nil {
|
||||
return gopay.NULL, gopay.NULL, fmt.Errorf("time.ParseInLocation(%s, %s),err:%w", xtime.TimeLayout, formatEffective, err)
|
||||
}
|
||||
eu := int(effectiveTime.Unix())
|
||||
effectiveTs = append(effectiveTs, eu)
|
||||
certMap[eu] = v
|
||||
}
|
||||
sort.Ints(effectiveTs)
|
||||
// newest cert
|
||||
newestCert := certMap[effectiveTs[len(effectiveTs)-1]]
|
||||
formatExpire := xtime.FormatDateTime(newestCert.ExpireTime)
|
||||
expireTime, err := time.ParseInLocation(xtime.TimeLayout, formatExpire, time.Local)
|
||||
if err != nil {
|
||||
return gopay.NULL, gopay.NULL, fmt.Errorf("time.ParseInLocation(%s, %s),err:%w", xtime.TimeLayout, formatExpire, err)
|
||||
}
|
||||
if time.Now().Unix() >= expireTime.Unix() {
|
||||
// 过期了
|
||||
return gopay.NULL, gopay.NULL, fmt.Errorf("wechat platform API cert expired, expired time: %s", formatExpire)
|
||||
}
|
||||
return newestCert.PublicKey, newestCert.SerialNo, nil
|
||||
}
|
||||
// failed
|
||||
return gopay.NULL, gopay.NULL, fmt.Errorf("GetAndSelectNewestCert() failed or certs is nil: %+v", certs)
|
||||
}
|
||||
|
||||
// 推荐直接使用 client.GetAndSelectNewestCert() 方法
|
||||
// 获取微信平台证书公钥(获取后自行保存使用,如需定期刷新功能,自行实现)
|
||||
// 注意事项
|
||||
// 如果自行实现验证平台签名逻辑的话,需要注意以下事项:
|
||||
// - 程序实现定期更新平台证书的逻辑,不要硬编码验证应答消息签名的平台证书
|
||||
// - 定期调用该接口,间隔时间小于12小时
|
||||
// - 加密请求消息中的敏感信息时,使用最新的平台证书(即:证书启用时间较晚的证书)
|
||||
// 文档说明:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay5_1.shtml
|
||||
func (c *ClientV3) getPlatformCerts() (certs *PlatformCertRsp, err error) {
|
||||
var (
|
||||
eg = new(errgroup.Group)
|
||||
mu sync.Mutex
|
||||
)
|
||||
|
||||
authorization, err := c.authorization(MethodGet, v3GetCerts, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, _, bs, err := c.doProdGet(c.ctx, v3GetCerts, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs = &PlatformCertRsp{Code: Success}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
certs.Code = res.StatusCode
|
||||
certs.Error = string(bs)
|
||||
return certs, nil
|
||||
}
|
||||
certRsp := new(PlatformCert)
|
||||
if err = json.Unmarshal(bs, certRsp); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s):%+v", string(bs), err)
|
||||
}
|
||||
for _, v := range certRsp.Data {
|
||||
cert := v
|
||||
if cert.EncryptCertificate != nil {
|
||||
ec := cert.EncryptCertificate
|
||||
eg.Go(func(ctx context.Context) error {
|
||||
pubKey, err := c.decryptCerts(ec.Ciphertext, ec.Nonce, ec.AssociatedData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pci := &PlatformCertItem{
|
||||
EffectiveTime: cert.EffectiveTime,
|
||||
ExpireTime: cert.ExpireTime,
|
||||
PublicKey: pubKey,
|
||||
SerialNo: cert.SerialNo,
|
||||
}
|
||||
mu.Lock()
|
||||
certs.Certs = append(certs.Certs, pci)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
if err = eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return certs, nil
|
||||
}
|
||||
|
||||
// 解密加密的证书
|
||||
func (c *ClientV3) decryptCerts(ciphertext, nonce, additional string) (wxCerts string, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), c.ApiV3Key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
return string(decrypt), nil
|
||||
}
|
||||
|
||||
func (c *ClientV3) autoCheckCertProc() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
buf := make([]byte, 64<<10)
|
||||
buf = buf[:runtime.Stack(buf, false)]
|
||||
xlog.Errorf("autoCheckCertProc: panic recovered: %s\n%s", r, buf)
|
||||
// 重启
|
||||
c.autoCheckCertProc()
|
||||
}
|
||||
}()
|
||||
for {
|
||||
time.Sleep(time.Hour * 12)
|
||||
wxPk, wxSerialNo, err := c.GetAndSelectNewestCert()
|
||||
if err != nil {
|
||||
xlog.Errorf("c.GetAndSelectNewestCert(),err:%+v", err)
|
||||
continue
|
||||
}
|
||||
// decode cert
|
||||
pubKey, err := xpem.DecodePublicKey([]byte(wxPk))
|
||||
if err != nil {
|
||||
xlog.Errorf("xpem.DecodePublicKey(%s),err:%+v", wxPk, err)
|
||||
continue
|
||||
}
|
||||
c.wxPublicKey = pubKey
|
||||
c.WxSerialNo = wxSerialNo
|
||||
}
|
||||
}
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
"github.com/go-pay/gopay/pkg/xhttp"
|
||||
"github.com/go-pay/gopay/pkg/xlog"
|
||||
"github.com/go-pay/gopay/pkg/xpem"
|
||||
)
|
||||
|
||||
// ClientV3 微信支付 V3
|
||||
type ClientV3 struct {
|
||||
Mchid string
|
||||
ApiV3Key []byte
|
||||
SerialNo string
|
||||
WxSerialNo string
|
||||
autoSign bool
|
||||
privateKey *rsa.PrivateKey
|
||||
wxPublicKey *rsa.PublicKey
|
||||
ctx context.Context
|
||||
DebugSwitch gopay.DebugSwitch
|
||||
}
|
||||
|
||||
// NewClientV3 初始化微信客户端 V3
|
||||
// mchid:商户ID 或者服务商模式的 sp_mchid
|
||||
// serialNo:商户API证书的证书序列号
|
||||
// apiV3Key:APIv3Key,商户平台获取
|
||||
// privateKey:商户API证书下载后,私钥 apiclient_key.pem 读取后的字符串内容
|
||||
func NewClientV3(mchid, serialNo, apiV3Key, privateKey string) (client *ClientV3, err error) {
|
||||
if mchid == util.NULL || serialNo == util.NULL || apiV3Key == util.NULL || privateKey == util.NULL {
|
||||
return nil, gopay.MissWechatInitParamErr
|
||||
}
|
||||
priKey, err := xpem.DecodePrivateKey([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client = &ClientV3{
|
||||
Mchid: mchid,
|
||||
SerialNo: serialNo,
|
||||
ApiV3Key: []byte(apiV3Key),
|
||||
privateKey: priKey,
|
||||
ctx: context.Background(),
|
||||
DebugSwitch: gopay.DebugOff,
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// AutoVerifySign 开启请求完自动验签功能(默认不开启,推荐开启)
|
||||
// 开启自动验签,自动开启每12小时一次轮询,请求最新证书操作
|
||||
func (c *ClientV3) AutoVerifySign() (err error) {
|
||||
wxPk, wxSerialNo, err := c.GetAndSelectNewestCert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// decode cert
|
||||
pubKey, err := xpem.DecodePublicKey([]byte(wxPk))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.wxPublicKey = pubKey
|
||||
c.WxSerialNo = wxSerialNo
|
||||
c.autoSign = true
|
||||
go c.autoCheckCertProc()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ClientV3) doProdPostWithHeader(ctx context.Context, headerMap map[string]string, bm gopay.BodyMap, path, authorization string) (res *http.Response, si *SignInfo, bs []byte, err error) {
|
||||
var url = v3BaseUrlCh + path
|
||||
httpClient := xhttp.NewClient()
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_V3_RequestBody: %s", bm.JsonBody())
|
||||
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
|
||||
}
|
||||
for k, v := range headerMap {
|
||||
httpClient.Header.Add(k, v)
|
||||
}
|
||||
httpClient.Header.Add(HeaderAuthorization, authorization)
|
||||
httpClient.Header.Add(HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
|
||||
httpClient.Header.Add(HeaderSerial, c.WxSerialNo)
|
||||
httpClient.Header.Add("Accept", "*/*")
|
||||
res, bs, err = httpClient.Type(xhttp.TypeJSON).Post(url).SendBodyMap(bm).EndBytes(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
si = &SignInfo{
|
||||
HeaderTimestamp: res.Header.Get(HeaderTimestamp),
|
||||
HeaderNonce: res.Header.Get(HeaderNonce),
|
||||
HeaderSignature: res.Header.Get(HeaderSignature),
|
||||
HeaderSerial: res.Header.Get(HeaderSerial),
|
||||
SignBody: string(bs),
|
||||
}
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_Response: %d > %s", res.StatusCode, string(bs))
|
||||
xlog.Debugf("Wechat_Headers: %#v", res.Header)
|
||||
xlog.Debugf("Wechat_SignInfo: %#v", si)
|
||||
}
|
||||
return res, si, bs, nil
|
||||
}
|
||||
|
||||
func (c *ClientV3) doProdPost(ctx context.Context, bm gopay.BodyMap, path, authorization string) (res *http.Response, si *SignInfo, bs []byte, err error) {
|
||||
var url = v3BaseUrlCh + path
|
||||
httpClient := xhttp.NewClient()
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_V3_RequestBody: %s", bm.JsonBody())
|
||||
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
|
||||
}
|
||||
httpClient.Header.Add(HeaderAuthorization, authorization)
|
||||
httpClient.Header.Add(HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
|
||||
httpClient.Header.Add(HeaderSerial, c.WxSerialNo)
|
||||
httpClient.Header.Add("Accept", "*/*")
|
||||
res, bs, err = httpClient.Type(xhttp.TypeJSON).Post(url).SendBodyMap(bm).EndBytes(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
si = &SignInfo{
|
||||
HeaderTimestamp: res.Header.Get(HeaderTimestamp),
|
||||
HeaderNonce: res.Header.Get(HeaderNonce),
|
||||
HeaderSignature: res.Header.Get(HeaderSignature),
|
||||
HeaderSerial: res.Header.Get(HeaderSerial),
|
||||
SignBody: string(bs),
|
||||
}
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_Response: %d > %s", res.StatusCode, string(bs))
|
||||
xlog.Debugf("Wechat_Headers: %#v", res.Header)
|
||||
xlog.Debugf("Wechat_SignInfo: %#v", si)
|
||||
}
|
||||
return res, si, bs, nil
|
||||
}
|
||||
|
||||
func (c *ClientV3) doProdGet(ctx context.Context, uri, authorization string) (res *http.Response, si *SignInfo, bs []byte, err error) {
|
||||
var url = v3BaseUrlCh + uri
|
||||
httpClient := xhttp.NewClient()
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_V3_Url: %s", url)
|
||||
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
|
||||
}
|
||||
httpClient.Header.Add(HeaderAuthorization, authorization)
|
||||
httpClient.Header.Add(HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
|
||||
httpClient.Header.Add(HeaderSerial, c.WxSerialNo)
|
||||
httpClient.Header.Add("Accept", "*/*")
|
||||
res, bs, err = httpClient.Type(xhttp.TypeJSON).Get(url).EndBytes(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
si = &SignInfo{
|
||||
HeaderTimestamp: res.Header.Get(HeaderTimestamp),
|
||||
HeaderNonce: res.Header.Get(HeaderNonce),
|
||||
HeaderSignature: res.Header.Get(HeaderSignature),
|
||||
HeaderSerial: res.Header.Get(HeaderSerial),
|
||||
SignBody: string(bs),
|
||||
}
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_Response: %d > %s", res.StatusCode, string(bs))
|
||||
xlog.Debugf("Wechat_Headers: %#v", res.Header)
|
||||
xlog.Debugf("Wechat_SignInfo: %#v", si)
|
||||
}
|
||||
return res, si, bs, nil
|
||||
}
|
||||
|
||||
func (c *ClientV3) doProdPut(ctx context.Context, bm gopay.BodyMap, path, authorization string) (res *http.Response, si *SignInfo, bs []byte, err error) {
|
||||
var url = v3BaseUrlCh + path
|
||||
httpClient := xhttp.NewClient()
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_V3_RequestBody: %s", bm.JsonBody())
|
||||
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
|
||||
}
|
||||
httpClient.Header.Add(HeaderAuthorization, authorization)
|
||||
httpClient.Header.Add(HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
|
||||
httpClient.Header.Add(HeaderSerial, c.WxSerialNo)
|
||||
httpClient.Header.Add("Accept", "*/*")
|
||||
res, bs, err = httpClient.Type(xhttp.TypeJSON).Put(url).SendBodyMap(bm).EndBytes(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
si = &SignInfo{
|
||||
HeaderTimestamp: res.Header.Get(HeaderTimestamp),
|
||||
HeaderNonce: res.Header.Get(HeaderNonce),
|
||||
HeaderSignature: res.Header.Get(HeaderSignature),
|
||||
HeaderSerial: res.Header.Get(HeaderSerial),
|
||||
SignBody: string(bs),
|
||||
}
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_Response: %d > %s", res.StatusCode, string(bs))
|
||||
xlog.Debugf("Wechat_Headers: %#v", res.Header)
|
||||
xlog.Debugf("Wechat_SignInfo: %#v", si)
|
||||
}
|
||||
return res, si, bs, nil
|
||||
}
|
||||
|
||||
func (c *ClientV3) doProdDelete(ctx context.Context, bm gopay.BodyMap, path, authorization string) (res *http.Response, si *SignInfo, bs []byte, err error) {
|
||||
var url = v3BaseUrlCh + path
|
||||
httpClient := xhttp.NewClient()
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_V3_RequestBody: %s", bm.JsonBody())
|
||||
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
|
||||
}
|
||||
httpClient.Header.Add(HeaderAuthorization, authorization)
|
||||
httpClient.Header.Add(HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
|
||||
httpClient.Header.Add(HeaderSerial, c.WxSerialNo)
|
||||
httpClient.Header.Add("Accept", "*/*")
|
||||
res, bs, err = httpClient.Type(xhttp.TypeJSON).Delete(url).SendBodyMap(bm).EndBytes(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
si = &SignInfo{
|
||||
HeaderTimestamp: res.Header.Get(HeaderTimestamp),
|
||||
HeaderNonce: res.Header.Get(HeaderNonce),
|
||||
HeaderSignature: res.Header.Get(HeaderSignature),
|
||||
HeaderSerial: res.Header.Get(HeaderSerial),
|
||||
SignBody: string(bs),
|
||||
}
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_Response: %d > %s", res.StatusCode, string(bs))
|
||||
xlog.Debugf("Wechat_Headers: %#v", res.Header)
|
||||
xlog.Debugf("Wechat_SignInfo: %#v", si)
|
||||
}
|
||||
return res, si, bs, nil
|
||||
}
|
||||
|
||||
func (c *ClientV3) doProdPostFile(ctx context.Context, bm gopay.BodyMap, path, authorization string) (res *http.Response, si *SignInfo, bs []byte, err error) {
|
||||
var url = v3BaseUrlCh + path
|
||||
httpClient := xhttp.NewClient()
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_V3_RequestBody: %s", bm.GetString("meta"))
|
||||
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
|
||||
}
|
||||
httpClient.Header.Add(HeaderAuthorization, authorization)
|
||||
httpClient.Header.Add(HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
|
||||
httpClient.Header.Add(HeaderSerial, c.WxSerialNo)
|
||||
httpClient.Header.Add("Accept", "*/*")
|
||||
res, bs, err = httpClient.Type(xhttp.TypeMultipartFormData).Post(url).SendMultipartBodyMap(bm).EndBytes(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
si = &SignInfo{
|
||||
HeaderTimestamp: res.Header.Get(HeaderTimestamp),
|
||||
HeaderNonce: res.Header.Get(HeaderNonce),
|
||||
HeaderSignature: res.Header.Get(HeaderSignature),
|
||||
HeaderSerial: res.Header.Get(HeaderSerial),
|
||||
SignBody: string(bs),
|
||||
}
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_Response: %d > %s", res.StatusCode, string(bs))
|
||||
xlog.Debugf("Wechat_Headers: %#v", res.Header)
|
||||
xlog.Debugf("Wechat_SignInfo: %#v", si)
|
||||
}
|
||||
return res, si, bs, nil
|
||||
}
|
||||
|
||||
func (c *ClientV3) doProdPatch(ctx context.Context, bm gopay.BodyMap, path, authorization string) (res *http.Response, si *SignInfo, bs []byte, err error) {
|
||||
var url = v3BaseUrlCh + path
|
||||
httpClient := xhttp.NewClient()
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_V3_RequestBody: %s", bm.JsonBody())
|
||||
xlog.Debugf("Wechat_V3_Authorization: %s", authorization)
|
||||
}
|
||||
httpClient.Header.Add(HeaderAuthorization, authorization)
|
||||
httpClient.Header.Add(HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
|
||||
httpClient.Header.Add(HeaderSerial, c.WxSerialNo)
|
||||
httpClient.Header.Add("Accept", "*/*")
|
||||
res, bs, err = httpClient.Type(xhttp.TypeJSON).Patch(url).SendBodyMap(bm).EndBytes(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
si = &SignInfo{
|
||||
HeaderTimestamp: res.Header.Get(HeaderTimestamp),
|
||||
HeaderNonce: res.Header.Get(HeaderNonce),
|
||||
HeaderSignature: res.Header.Get(HeaderSignature),
|
||||
HeaderSerial: res.Header.Get(HeaderSerial),
|
||||
SignBody: string(bs),
|
||||
}
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_Response: %d > %s", res.StatusCode, string(bs))
|
||||
xlog.Debugf("Wechat_Headers: %#v", res.Header)
|
||||
xlog.Debugf("Wechat_SignInfo: %#v", si)
|
||||
}
|
||||
return res, si, bs, nil
|
||||
}
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// 创建投诉通知回调地址API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_2.shtml
|
||||
func (c *ClientV3) V3ComplaintNotifyUrlCreate(ctx context.Context, url string) (wxRsp *ComplaintNotifyUrlRsp, err error) {
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("url", url)
|
||||
authorization, err := c.authorization(MethodPost, v3ComplaintNotifyUrlCreate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ComplaintNotifyUrlCreate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ComplaintNotifyUrlRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ComplaintNotifyUrl)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询投诉通知回调地址API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_3.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_3.shtml
|
||||
func (c *ClientV3) V3ComplaintNotifyUrlQuery(ctx context.Context) (wxRsp *ComplaintNotifyUrlRsp, err error) {
|
||||
authorization, err := c.authorization(MethodGet, v3ComplaintNotifyUrlQuery, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, v3ComplaintNotifyUrlQuery, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ComplaintNotifyUrlRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ComplaintNotifyUrl)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 更新投诉通知回调地址API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_4.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_4.shtml
|
||||
func (c *ClientV3) V3ComplaintNotifyUrlUpdate(ctx context.Context, url string) (wxRsp *ComplaintNotifyUrlRsp, err error) {
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("url", url)
|
||||
authorization, err := c.authorization(MethodPut, v3ComplaintNotifyUrlUpdate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPut(ctx, bm, v3ComplaintNotifyUrlUpdate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ComplaintNotifyUrlRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ComplaintNotifyUrl)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 删除投诉通知回调地址API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_5.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_5.shtml
|
||||
func (c *ClientV3) V3ComplaintNotifyUrlDelete(ctx context.Context) (wxRsp *EmptyRsp, err error) {
|
||||
authorization, err := c.authorization(MethodDelete, v3ComplaintNotifyUrlDelete, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdDelete(ctx, nil, v3ComplaintNotifyUrlDelete, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商户上传反馈图片API
|
||||
// 注意:图片不能超过2MB
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_10.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_10.shtml
|
||||
func (c *ClientV3) V3ComplaintUploadImage(ctx context.Context, fileName, fileSha256 string, img *util.File) (wxRsp *MediaUploadRsp, err error) {
|
||||
bmFile := make(gopay.BodyMap)
|
||||
bmFile.Set("filename", fileName).Set("sha256", fileSha256)
|
||||
authorization, err := c.authorization(MethodPost, v3ComplaintUploadImage, bmFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.SetBodyMap("meta", func(bm gopay.BodyMap) {
|
||||
bm.Set("filename", fileName).Set("sha256", fileSha256)
|
||||
}).SetFormFile("file", img)
|
||||
res, si, bs, err := c.doProdPostFile(ctx, bm, v3ComplaintUploadImage, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &MediaUploadRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(MediaUpload)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询投诉单列表API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_11.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_11.shtml
|
||||
func (c *ClientV3) V3ComplaintList(ctx context.Context, bm gopay.BodyMap) (wxRsp *ComplaintListRsp, err error) {
|
||||
uri := v3ComplaintList + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ComplaintListRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ComplaintList)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询投诉协商历史API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_12.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_12.shtml
|
||||
func (c *ClientV3) V3ComplaintNegotiationHistory(ctx context.Context, complaintId string, bm gopay.BodyMap) (wxRsp *ComplaintNegotiationHistoryRsp, err error) {
|
||||
uri := fmt.Sprintf(v3ComplaintNegotiationHistory, complaintId) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ComplaintNegotiationHistoryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ComplaintNegotiationHistory)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询投诉单详情API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_13.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_13.shtml
|
||||
func (c *ClientV3) V3ComplaintDetail(ctx context.Context, complaintId string) (wxRsp *ComplaintDetailRsp, err error) {
|
||||
url := fmt.Sprintf(v3ComplaintDetail, complaintId)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ComplaintDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ComplaintDetail)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 提交回复API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_14.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_14.shtml
|
||||
func (c *ClientV3) V3ComplaintResponse(ctx context.Context, complaintId string, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
url := fmt.Sprintf(v3ComplaintResponse, complaintId)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 反馈处理完成API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_15.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_15.shtml
|
||||
func (c *ClientV3) V3ComplaintComplete(ctx context.Context, complaintId string, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
url := fmt.Sprintf(v3ComplaintComplete, complaintId)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
package wechat
|
||||
|
||||
const (
|
||||
Success = 0
|
||||
SignTypeRSA = "RSA"
|
||||
|
||||
MethodGet = "GET"
|
||||
MethodPost = "POST"
|
||||
MethodPut = "PUT"
|
||||
MethodDelete = "DELETE"
|
||||
MethodPATCH = "PATCH"
|
||||
HeaderAuthorization = "Authorization"
|
||||
HeaderRequestID = "Request-ID"
|
||||
|
||||
HeaderTimestamp = "Wechatpay-Timestamp"
|
||||
HeaderNonce = "Wechatpay-Nonce"
|
||||
HeaderSignature = "Wechatpay-Signature"
|
||||
HeaderSerial = "Wechatpay-Serial"
|
||||
|
||||
Authorization = "WECHATPAY2-SHA256-RSA2048"
|
||||
|
||||
v3BaseUrlCh = "https://api.mch.weixin.qq.com" // 中国国内
|
||||
|
||||
v3GetCerts = "/v3/certificates"
|
||||
// 基础支付(直连模式)
|
||||
v3ApiApp = "/v3/pay/transactions/app" // APP 下单
|
||||
v3ApiJsapi = "/v3/pay/transactions/jsapi" // JSAPI 下单
|
||||
v3ApiNative = "/v3/pay/transactions/native" // Native 下单
|
||||
v3ApiH5 = "/v3/pay/transactions/h5" // H5 下单
|
||||
v3ApiQueryOrderTransactionId = "/v3/pay/transactions/id/%s" // transaction_id 查询订单
|
||||
v3ApiQueryOrderOutTradeNo = "/v3/pay/transactions/out-trade-no/%s" // out_trade_no 查询订单
|
||||
v3ApiCloseOrder = "/v3/pay/transactions/out-trade-no/%s/close" // out_trade_no 关闭订单
|
||||
|
||||
// 基础支付(服务商模式)
|
||||
v3ApiPartnerPayApp = "/v3/pay/partner/transactions/app" // partner APP 下单
|
||||
v3ApiPartnerJsapi = "/v3/pay/partner/transactions/jsapi" // partner JSAPI 下单
|
||||
v3ApiPartnerNative = "/v3/pay/partner/transactions/native" // partner Native 下单
|
||||
v3ApiPartnerH5 = "/v3/pay/partner/transactions/h5" // partner H5 下单
|
||||
v3ApiPartnerQueryOrderTransactionId = "/v3/pay/partner/transactions/id/%s" // partner transaction_id 查询订单
|
||||
v3ApiPartnerQueryOrderOutTradeNo = "/v3/pay/partner/transactions/out-trade-no/%s" // partner out_trade_no 查询订单
|
||||
v3ApiPartnerCloseOrder = "/v3/pay/partner/transactions/out-trade-no/%s/close" // partner out_trade_no 关闭订单
|
||||
|
||||
// 基础支付(合单支付)
|
||||
v3CombinePayApp = "/v3/combine-transactions/app"
|
||||
v3CombinePayH5 = "/v3/combine-transactions/h5"
|
||||
v3CombinePayJsapi = "/v3/combine-transactions/jsapi"
|
||||
v3CombineNative = "/v3/combine-transactions/native"
|
||||
v3CombineQuery = "/v3/combine-transactions/out-trade-no/%s"
|
||||
v3CombineClose = "/v3/combine-transactions/out-trade-no/%s/close"
|
||||
|
||||
// 退款
|
||||
v3DomesticRefund = "/v3/refund/domestic/refunds" // 申请退款
|
||||
v3DomesticRefundQuery = "/v3/refund/domestic/refunds/%s" // 查询单笔退款
|
||||
|
||||
// 账单
|
||||
v3TradeBill = "/v3/bill/tradebill" // 申请交易账单 GET
|
||||
v3FundFlowBill = "/v3/bill/fundflowbill" // 申请资金账单 GET
|
||||
v3EcommerceFundFlowBill = "/v3/ecommerce/bill/fundflowbill" // 申请特约商户资金账单 GET
|
||||
v3SubFundFlowBill = "/v3/bill/sub-merchant-fundflowbill" // 申请单个子商户资金账单 GET
|
||||
|
||||
// 提现
|
||||
v3Withdraw = "/v3/ecommerce/fund/withdraw" // 特约商户余额提现 POST
|
||||
v3WithdrawStatusById = "/v3/ecommerce/fund/withdraw/%s" // withdraw_id 查询特约商户提现状态 GET
|
||||
v3WithdrawStatusByNo = "/v3/ecommerce/fund/withdraw/out-request-no/%s" // out_request_no 查询特约商户提现状态 GET
|
||||
v3EcommerceWithdraw = "/v3/merchant/fund/withdraw" // 电商平台预约提现 POST
|
||||
v3EcommerceWithdrawStatusById = "/v3/merchant/fund/withdraw/withdraw-id/%s" // withdraw_id 电商平台查询预约提现状态 POST
|
||||
v3EcommerceWithdrawStatusByNo = "/v3/merchant/fund/withdraw/out-request-no/%s" // out_request_no 电商平台查询预约提现状态 POST
|
||||
v3WithdrawDownloadErrBill = "/v3/merchant/fund/withdraw/bill-type/%s" // bill_type 按日下载提现异常文件 GET
|
||||
|
||||
// 微信支付分(免确认模式)
|
||||
v3ScoreDirectComplete = "/payscore/serviceorder/direct-complete" // 创单结单合并 POST
|
||||
|
||||
// 微信支付分(免确认预授权模式)
|
||||
v3ScorePermission = "/v3/payscore/permissions" // 商户预授权 POST
|
||||
v3ScorePermissionQuery = "/v3/payscore/permissions/authorization-code/%s" // authorization_code 查询用户授权记录(授权协议号) GET
|
||||
v3ScorePermissionTerminate = "/v3/payscore/permissions/authorization-code/%s/terminate" // authorization_code 解除用户授权关系(授权协议号) POST
|
||||
v3ScorePermissionOpenidQuery = "/v3/payscore/permissions/openid/%s" // openid 查询用户授权记录(openid) GET
|
||||
v3ScorePermissionOpenidTerminate = "/v3/payscore/permissions/openid/%s/terminate" // openid 解除用户授权记录(openid) POST
|
||||
|
||||
// 微信支付分(公共API)
|
||||
v3ScoreOrderCreate = "/v3/payscore/serviceorder" // 创建支付分订单 POST
|
||||
v3ScoreOrderQuery = "/v3/payscore/serviceorder" // 查询支付分订单 GET
|
||||
v3ScoreOrderCancel = "/v3/payscore/serviceorder/%s/cancel" // out_trade_no 取消支付分订单 POST
|
||||
v3ScoreOrderModify = "/v3/payscore/serviceorder/%s/modify" // out_trade_no 修改订单金额 POST
|
||||
v3ScoreOrderComplete = "/v3/payscore/serviceorder/%s/complete" // out_trade_no 完结支付分订单 POST
|
||||
v3ScoreOrderPay = "/v3/payscore/serviceorder/%s/pay" // out_trade_no 商户发起催收扣款 POST
|
||||
v3ScoreOrderSync = "/v3/payscore/serviceorder/%s/sync" // out_trade_no 同步服务订单信息 POST
|
||||
|
||||
// 微信先享卡
|
||||
v3CardPre = "/v3/discount-card/cards" // 预受理领卡请求 POST
|
||||
v3CardAddUser = "/v3/discount-card/cards/%s/add-user-records" // out_card_code 增加用户记录 POST
|
||||
v3CardQuery = "/v3/discount-card/cards/%s" // out_card_code 查询先享卡订单 GET
|
||||
|
||||
// 支付即服务
|
||||
v3GuideReg = "/v3/smartguide/guides" // 服务人员注册 POST
|
||||
v3GuideAssign = "/v3/smartguide/guides/%s/assign" // guide_id 服务人员分配 POST
|
||||
v3GuideQuery = "/v3/smartguide/guides" // 服务人员查询 GET
|
||||
v3GuideUpdate = "/v3/smartguide/guides/%s" // guide_id 服务人员信息更新 PATCH
|
||||
|
||||
// 智慧商圈
|
||||
v3BusinessPointsSync = "/v3/businesscircle/points/notify" // 商圈积分同步 POST
|
||||
v3BusinessAuthPointsQuery = "/v3/businesscircle/user-authorizations/%s" // openid 商圈积分授权查询 GET
|
||||
|
||||
// 代金券
|
||||
v3FavorBatchCreate = "/v3/marketing/favor/coupon-stocks" // 创建代金券批次 POST
|
||||
v3FavorBatchStart = "/v3/marketing/favor/stocks/%s/start" // stock_id 激活代金券批次 POST
|
||||
v3FavorBatchGrant = "/v3/marketing/favor/users/%s/coupons" // openid 发放代金券批次 POST
|
||||
v3FavorBatchPause = "/v3/marketing/favor/stocks/%s/pause" // stock_id 暂停代金券批次 POST
|
||||
v3FavorBatchRestart = "/v3/marketing/favor/stocks/%s/restart" // stock_id 重启代金券批次 POST
|
||||
v3FavorBatchList = "/v3/marketing/favor/stocks" // 条件查询批次列表 GET
|
||||
v3FavorBatchDetail = "/v3/marketing/favor/stocks/%s" // stock_id 查询批次详情 GET
|
||||
v3FavorDetail = "/v3/marketing/favor/users/%s/coupons/%s" // openid、coupon_id 查询代金券详情 GET
|
||||
v3FavorMerchant = "/v3/marketing/favor/stocks/%s/merchants" // stock_id 查询代金券可用商户 GET
|
||||
v3FavorItems = "/v3/marketing/favor/stocks/%s/items" // stock_id 查询代金券可用单品 GET
|
||||
v3FavorUserCoupons = "/v3/marketing/favor/users/%s/coupons" // openid 根据商户号查用户的券 GET
|
||||
v3FavorUseFlowDownload = "/v3/marketing/favor/stocks/%s/use-flow" // stock_id 下载批次核销明细 GET
|
||||
v3FavorRefundFlowDownload = "/v3/marketing/favor/stocks/%s/refund-flow" // stock_id 下载批次退款明细 GET
|
||||
v3FavorCallbackUrlSet = "/v3/marketing/favor/callbacks" // 设置消息通知地址 POST
|
||||
v3FavorMediaUploadImage = "/v3/marketing/favor/media/image-upload" // 图片上传(营销专用) POST
|
||||
|
||||
// 商家券
|
||||
v3BusiFavorBatchCreate = "/v3/marketing/busifavor/stocks" // 创建商家券 POST
|
||||
v3BusiFavorBatchDetail = "/v3/marketing/busifavor/stocks/%s" // stock_id 查询商家券详情 GET
|
||||
v3BusiFavorUse = "/v3/marketing/busifavor/coupons/use" // 核销用户券 POST
|
||||
v3BusiFavorUserCoupons = "/v3/marketing/busifavor/users/%s/coupons" // openid 根据过滤条件查询用户券 GET
|
||||
v3BusiFavorUserCouponDetail = "/v3/marketing/busifavor/users/%s/coupons/%s/appids/%s" // openid、coupon_code、appid 查询用户单张券详情 GET
|
||||
v3BusiFavorCodeUpload = "/v3/marketing/busifavor/stocks/%s/couponcodes" // stock_id 上传预存code POST
|
||||
v3BusiFavorCallbackUrlSet = "/v3/marketing/busifavor/callbacks" // 设置商家券事件通知地址 POST
|
||||
v3BusiFavorCallbackUrl = "/v3/marketing/busifavor/callbacks" // 查询商家券事件通知地址 GET
|
||||
v3BusiFavorAssociate = "/v3/marketing/busifavor/coupons/associate" // 关联订单信息 POST
|
||||
v3BusiFavorDisassociate = "/v3/marketing/busifavor/coupons/disassociate" // 取消关联订单信息 POST
|
||||
v3BusiFavorBatchUpdate = "/v3/marketing/busifavor/stocks/%s/budget" // stock_id 修改批次预算 PATCH
|
||||
v3BusiFavorInfoUpdate = "/v3/marketing/busifavor/stocks/%s" // stock_id 修改商家券基本信息 PATCH
|
||||
v3BusiFavorSend = "/v3/marketing/busifavor/coupons/%s/send" // card_id 发放消费卡 POST
|
||||
v3BusiFavorReturn = "/v3/marketing/busifavor/coupons/return" // 申请退券 POST
|
||||
v3BusiFavorDeactivate = "/v3/marketing/busifavor/coupons/deactivate" // 使券失效 POST
|
||||
v3BusiFavorSubsidyPay = "/v3/marketing/busifavor/subsidy/pay-receipts" // 营销补差付款 POST
|
||||
v3BusiFavorSubsidyPayDetail = "/v3/marketing/busifavor/subsidy/pay-receipts/%s" // subsidy_receipt_id 查询营销补差付款单详情 GET
|
||||
|
||||
// 委托营销(合作伙伴)
|
||||
v3PartnershipsBuild = "/v3/marketing/partnerships/build" // 建立合作关系 POST
|
||||
v3PartnershipsTerminate = "/v3/marketing/partnerships/terminate" // 终止合作关系 POST
|
||||
v3PartnershipsList = "/v3/marketing/partnerships" // 查询合作关系列表 GET
|
||||
|
||||
// 点金计划(服务商)
|
||||
v3GoldPlanManage = "/v3/goldplan/merchants/changegoldplanstatus" // 点金计划管理 POST
|
||||
v3GoldPlanBillManage = "/v3/goldplan/merchants/changecustompagestatus" // 商家小票管理 POST
|
||||
v3GoldPlanFilterManage = "/v3/goldplan/merchants/set-advertising-industry-filter" // 同业过滤标签管理 POST
|
||||
v3GoldPlanOpenAdShow = "/v3/goldplan/merchants/open-advertising-show" // 开通广告展示 PATCH
|
||||
v3GoldPlanCloseAdShow = "/v3/goldplan/merchants/close-advertising-show" // 关闭广告展示 POST
|
||||
|
||||
// 消费者投诉2.0
|
||||
v3ComplaintList = "/v3/merchant-service/complaints-v2" // 查询投诉单列表 GET
|
||||
v3ComplaintDetail = "/v3/merchant-service/complaints-v2/%s" // 查询投诉单详情 GET
|
||||
v3ComplaintNegotiationHistory = "/v3/merchant-service/complaints-v2/%s/negotiation-historys" // 查询投诉协商历史 GET
|
||||
v3ComplaintNotifyUrlCreate = "/v3/merchant-service/complaint-notifications" // 创建投诉通知回调地址 POST
|
||||
v3ComplaintNotifyUrlQuery = "/v3/merchant-service/complaint-notifications" // 查询投诉通知回调地址 GET
|
||||
v3ComplaintNotifyUrlUpdate = "/v3/merchant-service/complaint-notifications" // 查询投诉通知回调地址 PUT
|
||||
v3ComplaintNotifyUrlDelete = "/v3/merchant-service/complaint-notifications" // 删除投诉通知回调地址 DELETE
|
||||
v3ComplaintResponse = "/v3/merchant-service/complaints-v2/%s/response" // 提交回复 POST
|
||||
v3ComplaintComplete = "/v3/merchant-service/complaints-v2/%s/complete" // 反馈处理完成 POST
|
||||
v3ComplaintUploadImage = "/v3/merchant-service/images/upload" // 商户上传反馈图片 POST
|
||||
|
||||
// 分账(服务商)
|
||||
v3ProfitShareOrder = "/v3/profitsharing/orders" // 请求分账 POST
|
||||
v3ProfitShareQuery = "/v3/profitsharing/orders/%s" // 查询分账结果 GET
|
||||
v3ProfitShareReturn = "/v3/profitsharing/return-orders" // 请求分账回退 POST
|
||||
v3ProfitShareReturnResult = "/v3/profitsharing/return-orders/%s" // 查询分账回退结果 GET
|
||||
v3ProfitShareUnfreeze = "/v3/profitsharing/orders/unfreeze" // 解冻剩余资金 POST
|
||||
v3ProfitShareUnsplitAmount = "/v3/profitsharing/transactions/%s/amounts" // 查询剩余待分金额 GET
|
||||
v3ProfitShareAddReceiver = "/v3/profitsharing/receivers/add" // 添加分账接收方 POST
|
||||
v3ProfitShareDeleteReceiver = "/v3/profitsharing/receivers/delete" // 删除分账接收方 POST
|
||||
v3ProfitShareMerchantConfigs = "/v3/profitsharing/merchant-configs/%s" // 查询最大分账比例API GET
|
||||
v3ProfitShareBills = "/v3/profitsharing/bills" // 申请分账账单 GET
|
||||
|
||||
// 其他能力
|
||||
v3MediaUploadImage = "/v3/merchant/media/upload" // 图片上传 POST
|
||||
v3MediaUploadVideo = "/v3/merchant/media/video_upload" // 视频上传 POST
|
||||
|
||||
// 转账
|
||||
v3Transfer = "/v3/transfer/batches" // 发起批量转账 POST
|
||||
v3TransferQuery = "/v3/transfer/batches/batch-id/%s" // batch_id 微信批次单号查询批次单 GET
|
||||
v3TransferDetail = "/v3/transfer/batches/batch-id/%s/details/detail-id/%s" // batch_id、detail_id 微信明细单号查询明细单 GET
|
||||
v3TransferMerchantQuery = "/v3/transfer/batches/out-batch-no/%s" // out_batch_no 商家批次单号查询批次单 GET
|
||||
v3TransferMerchantDetail = "/v3/transfer/batches/out-batch-no/%s/details/out-detail-no/%s" // out_batch_no、out_detail_no 商家明细单号查询明细单 GET
|
||||
v3TransferReceipt = "/v3/transfer/bill-receipt" // 转账电子回单申请受理 POST
|
||||
v3TransferReceiptQuery = "/v3/transfer/bill-receipt/%s" // out_batch_no 查询转账电子回单 GET
|
||||
v3TransferDetailReceipt = "/v3/transfer-detail/electronic-receipts" // 转账明细电子回单受理 POST
|
||||
v3TransferDetailReceiptQuery = "/v3/transfer-detail/electronic-receipts" // 查询转账明细电子回单受理结果 GET
|
||||
|
||||
// 转账(服务商)
|
||||
v3PartnerTransfer = "/v3/partner-transfer/batches" // 发起批量转账 POST
|
||||
v3PartnerTransferQuery = "/v3/partner-transfer/batches/batch-id/%s" // batch_id 微信批次单号查询批次单 GET
|
||||
v3PartnerTransferDetail = "/v3/partner-transfer/batches/batch-id/%s/details/detail-id/%s" // batch_id、detail_id 微信明细单号查询明细单 GET
|
||||
v3PartnerTransferMerchantQuery = "/v3/partner-transfer/batches/out-batch-no/%s" // out_batch_no 商家批次单号查询批次单 GET
|
||||
v3PartnerTransferMerchantDetail = "/v3/partner-transfer/batches/out-batch-no/%s/details/out-detail-no/%s" // out_batch_no、out_detail_no 商家明细单号查询明细单 GET
|
||||
|
||||
// 余额
|
||||
v3MerchantBalance = "/v3/merchant/fund/balance/%s" // account_type 查询账户实时余额 GET
|
||||
v3MerchantDayBalance = "/v3/merchant/fund/dayendbalance/%s" // account_type 查询账户日终余额 GET
|
||||
v3EcommerceBalance = "/v3/ecommerce/fund/balance/%s" // sub_mchid 查询特约商户账户实时余额 GET
|
||||
v3EcommerceDayBalance = "/v3/ecommerce/fund/enddaybalance/%s" // sub_mchid 查询二级商户账户日终余额 GET
|
||||
|
||||
// 来账识别API
|
||||
v3MerchantIncomeRecord = "/v3/merchantfund/merchant/income-records" // 商户银行来账查询 GET
|
||||
v3EcommerceIncomeRecord = "/v3/merchantfund/partner/income-records" // 特约商户银行来账查询 GET
|
||||
|
||||
// 服务商-特约商户进件
|
||||
v3Apply4SubSubmit = "/v3/applyment4sub/applyment/" // 提交申请单 POST
|
||||
v3Apply4SubQueryByBusinessCode = "/v3/applyment4sub/applyment/business_code/%s" // business_code 通过业务申请编号查询申请状态 GET
|
||||
v3Apply4SubQueryByApplyId = "/v3/applyment4sub/applyment/applyment_id/%s" // applyment_id 通过申请单号查询申请状态 GET
|
||||
v3Apply4SubModifySettlement = "/v3/apply4sub/sub_merchants/%s/modify-settlement" // sub_mchid 修改结算账号 POST
|
||||
v3Apply4SubQuerySettlement = "/v3/apply4sub/sub_merchants/%s/settlement" // sub_mchid 查询结算账户 GET
|
||||
|
||||
// 电商收付通(商户进件)
|
||||
v3EcommerceApply = "/v3/ecommerce/applyments/" // 二级商户进件 POST
|
||||
v3EcommerceApplyQueryById = "/v3/ecommerce/applyments/%d" // applyment_id 通过申请单ID查询申请状态 GET
|
||||
v3EcommerceApplyQueryByNo = "/v3/ecommerce/applyments/out-request-no/%s" // out_request_no 通过业务申请编号查询申请状态 GET
|
||||
|
||||
// 电商收付通(分账)
|
||||
v3EcommerceProfitShare = "/v3/ecommerce/profitsharing/orders" // 请求分账 POST
|
||||
v3EcommerceProfitShareQuery = "/v3/ecommerce/profitsharing/orders" // 查询分账结果 GET
|
||||
v3EcommerceProfitShareReturn = "/v3/ecommerce/profitsharing/returnorders" // 请求分账回退 POST
|
||||
v3EcommerceProfitShareReturnResult = "/v3/ecommerce/profitsharing/returnorders" // 查询分账回退结果 GET
|
||||
v3EcommerceProfitShareFinish = "/v3/ecommerce/profitsharing/finish-order" // 完结分账 POST
|
||||
v3EcommerceProfitShareUnsplitAmount = "/v3/ecommerce/profitsharing/orders/%s/amounts" // transaction_id 查询订单剩余待分金额 GET
|
||||
v3EcommerceProfitShareAddReceiver = "/v3/ecommerce/profitsharing/receivers/add" // 添加分账接收方 POST
|
||||
v3EcommerceProfitShareDeleteReceiver = "/v3/ecommerce/profitsharing/receivers/delete" // 删除分账接收方 POST
|
||||
|
||||
// 电商收付通(补差)
|
||||
v3EcommerceSubsidies = "/v3/ecommerce/subsidies/create" // 请求补差 POST
|
||||
v3EcommerceSubsidiesReturn = "/v3/ecommerce/subsidies/return" // 请求补差回退 POST
|
||||
v3EcommerceSubsidiesCancel = "/v3/ecommerce/subsidies/cancel" // 取消补差 POST
|
||||
|
||||
// 电商收付通(退款)
|
||||
v3CommerceRefund = "/v3/ecommerce/refunds/apply" // 申请退款 POST
|
||||
v3CommerceRefundQueryById = "/v3/ecommerce/refunds/id/%s" // refund_id 通过微信支付退款单号查询退款 GET
|
||||
v3CommerceRefundQueryByNo = "/v3/ecommerce/refunds/out-refund-no/%s" // out_refund_no 通过商户退款单号查询退款 GET
|
||||
v3CommerceRefundAdvance = "/v3/ecommerce/refunds/%s/return-advance" // refund_id 垫付退款回补 POST
|
||||
v3CommerceRefundAdvanceResult = "/v3/ecommerce/refunds/%s/return-advance" // refund_id 查询垫付回补结果 GET
|
||||
|
||||
// 银行组件(服务商)
|
||||
v3BankSearchBank = "/v3/capital/capitallhh/banks/search-banks-by-bank-account" // 获取对私银行卡号开户银行 GET
|
||||
v3BankSearchPersonalList = "/v3/capital/capitallhh/banks/personal-banking" // 查询支持个人业务的银行列表 GET
|
||||
v3BankSearchCorporateList = "/v3/capital/capitallhh/banks/corporate-banking" // 查询支持对公业务的银行列表 GET
|
||||
v3BankSearchProvinceList = "/v3/capital/capitallhh/areas/provinces" // 查询省份列表 GET
|
||||
v3BankSearchCityList = "/v3/capital/capitallhh/areas/provinces/%d/cities" // province_code 查询城市列表 GET
|
||||
v3BankSearchBranchList = "/v3/capital/capitallhh/banks/%s/branches" // bank_alias_code 查询支行列表 GET
|
||||
|
||||
// 特约商户进件申请单状态
|
||||
ApplyStateEditing = "APPLYMENT_STATE_EDITTING" // 编辑中
|
||||
ApplyStateAuditing = "APPLYMENT_STATE_AUDITING" // 审核中
|
||||
ApplyStateRejected = "APPLYMENT_STATE_REJECTED" // 已驳回
|
||||
ApplyStateToBeConfirmed = "APPLYMENT_STATE_TO_BE_CONFIRMED" // 待账户验证
|
||||
ApplyStateSigning = "APPLYMENT_STATE_SIGNING" // 开通权限中
|
||||
ApplyStateFinished = "APPLYMENT_STATE_FINISHED" // 已完成
|
||||
ApplyStateCanceled = "APPLYMENT_STATE_CANCELED" // 已作废
|
||||
|
||||
// 特约商户结算账号类型
|
||||
ApplySettlementAccountTypeBusiness = "ACCOUNT_TYPE_BUSINESS" // 对公银行账户
|
||||
ApplySettlementAccountTypePrivate = "ACCOUNT_TYPE_PRIVATE" // 经营者个人银行卡
|
||||
|
||||
// 特约商户结算账号汇款验证结果
|
||||
ApplySettlementVerifying = "VERIFYING" // 系统汇款验证中,商户可发起提现尝试
|
||||
ApplySettlementVerifySuccess = "VERIFY_SUCCESS" // 系统成功汇款,该账户可正常发起提现
|
||||
ApplySettlementVerifyFail = "VERIFY_FAIL" // 系统汇款失败,该账户无法发起提现,请检查修改
|
||||
|
||||
// 订单号类型,1-微信订单号,2-商户订单号,3-微信侧回跳到商户前端时用于查单的单据查询id(查询支付分订单中会使用)
|
||||
TransactionId OrderNoType = 1
|
||||
OutTradeNo OrderNoType = 2
|
||||
QueryId OrderNoType = 3
|
||||
|
||||
// v3 异步通知订单状态
|
||||
TradeStateSuccess = "SUCCESS" // 支付成功
|
||||
TradeStateRefund = "REFUND" // 转入退款
|
||||
TradeStateNoPay = "NOTPAY" // 未支付
|
||||
TradeStateClosed = "CLOSED" // 已关闭
|
||||
TradeStateRevoked = "REVOKED" // 已撤销(付款码支付)
|
||||
TradeStatePaying = "USERPAYING" // 用户支付中(付款码支付)
|
||||
TradeStatePayError = "PAYERROR" // 支付失败(其他原因,如银行返回失败)
|
||||
)
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 预受理领卡请求API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_3_1.shtml
|
||||
func (c *ClientV3) V3DiscountCardApply(ctx context.Context, bm gopay.BodyMap) (wxRsp *DiscountCardApplyRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3CardPre, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3CardPre, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &DiscountCardApplyRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(DiscountCardApply)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 增加用户记录API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_3_2.shtml
|
||||
func (c *ClientV3) V3DiscountCardAddUser(ctx context.Context, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
if err = bm.CheckEmptyError("out_card_code"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uri := fmt.Sprintf(v3CardAddUser, bm.GetString("out_card_code"))
|
||||
bm.Remove("out_card_code")
|
||||
authorization, err := c.authorization(MethodPost, uri, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询先享卡订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_3_3.shtml
|
||||
func (c *ClientV3) V3DiscountCardQuery(ctx context.Context, outCardCode string) (wxRsp *DiscountCardQueryRsp, err error) {
|
||||
url := fmt.Sprintf(v3CardQuery, outCardCode)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &DiscountCardQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(DiscountCardQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+360
@@ -0,0 +1,360 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 二级商户进件API
|
||||
// 注意:本接口会提交一些敏感信息,需调用 client.V3EncryptText() 进行加密。部分图片参数,请先调用 client.V3MediaUploadImage() 上传,获取MediaId
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_1.shtml
|
||||
func (c *ClientV3) V3EcommerceApply(ctx context.Context, bm gopay.BodyMap) (*EcommerceApplyRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceApply, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceApply, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &EcommerceApplyRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceApply)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询申请状态API
|
||||
// 注意:applyId 和 outRequestNo 二选一
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_2.shtml
|
||||
func (c *ClientV3) V3EcommerceApplyStatus(ctx context.Context, applyId int64, outRequestNo string) (*EcommerceApplyStatusRsp, error) {
|
||||
if applyId == 0 && outRequestNo == gopay.NULL {
|
||||
return nil, fmt.Errorf("applyId[%d] and outRequestNo[%s] empty at the same time", applyId, outRequestNo)
|
||||
}
|
||||
var url string
|
||||
if applyId != 0 {
|
||||
url = fmt.Sprintf(v3EcommerceApplyQueryById, applyId)
|
||||
} else {
|
||||
url = fmt.Sprintf(v3EcommerceApplyQueryByNo, outRequestNo)
|
||||
}
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &EcommerceApplyStatusRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceApplyStatus)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 请求分账API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_1.shtml
|
||||
func (c *ClientV3) V3EcommerceProfitShare(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceProfitShare, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShare, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceProfitShareRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceProfitShare)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询分账结果API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_2.shtml
|
||||
func (c *ClientV3) V3EcommerceProfitShareQuery(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareQueryRsp, error) {
|
||||
uri := v3EcommerceProfitShareQuery + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceProfitShareQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceProfitShareQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 请求分账回退API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_3.shtml
|
||||
func (c *ClientV3) V3EcommerceProfitShareReturn(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareReturnRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceProfitShareReturn, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShareReturn, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceProfitShareReturnRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceProfitShareReturn)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询分账回退结果API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_4.shtml
|
||||
func (c *ClientV3) V3EcommerceProfitShareReturnResult(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareReturnResultRsp, error) {
|
||||
uri := v3EcommerceProfitShareReturnResult + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceProfitShareReturnResultRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceProfitShareReturn)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 完结分账API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_5.shtml
|
||||
func (c *ClientV3) V3EcommerceProfitShareFinish(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareFinishRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceProfitShareFinish, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShareFinish, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceProfitShareFinishRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceProfitShareFinish)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询订单剩余待分金额API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_9.shtml
|
||||
func (c *ClientV3) V3EcommerceProfitShareUnsplitAmount(ctx context.Context, transactionId string) (*EcommerceProfitShareUnsplitAmountRsp, error) {
|
||||
url := fmt.Sprintf(v3EcommerceProfitShareUnsplitAmount, transactionId)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceProfitShareUnsplitAmountRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceProfitShareUnsplitAmount)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 添加分账接收方API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_7.shtml
|
||||
func (c *ClientV3) V3EcommerceProfitShareAddReceiver(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareAddReceiverRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceProfitShareAddReceiver, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShareAddReceiver, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceProfitShareAddReceiverRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceProfitShareReceiver)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 删除分账接收方API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_8.shtml
|
||||
func (c *ClientV3) V3EcommerceProfitShareDeleteReceiver(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareDeleteReceiverRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceProfitShareDeleteReceiver, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShareDeleteReceiver, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceProfitShareDeleteReceiverRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceProfitShareReceiver)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 请求补差API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_5_1.shtml
|
||||
func (c *ClientV3) V3EcommerceSubsidies(ctx context.Context, bm gopay.BodyMap) (*EcommerceSubsidiesRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceSubsidies, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceSubsidies, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceSubsidiesRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceSubsidies)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 请求补差回退API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_5_2.shtml
|
||||
func (c *ClientV3) V3EcommerceSubsidiesReturn(ctx context.Context, bm gopay.BodyMap) (*EcommerceSubsidiesReturnRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceSubsidiesReturn, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceSubsidiesReturn, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceSubsidiesReturnRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceSubsidiesReturn)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 取消补差API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_5_3.shtml
|
||||
func (c *ClientV3) V3EcommerceSubsidiesCancel(ctx context.Context, bm gopay.BodyMap) (*EcommerceSubsidiesCancelRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceSubsidiesCancel, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceSubsidiesCancel, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceSubsidiesCancelRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceSubsidiesCancel)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/aes"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
"github.com/go-pay/gopay/pkg/xpem"
|
||||
)
|
||||
|
||||
// 敏感信息加密
|
||||
func (c *ClientV3) V3EncryptText(text string) (cipherText string, err error) {
|
||||
if c.wxPublicKey == nil || c.WxSerialNo == "" {
|
||||
return util.NULL, errors.New("WxPublicKey or WxSerialNo is null")
|
||||
}
|
||||
cipherByte, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, c.wxPublicKey, []byte(text), nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("rsa.EncryptOAEP:%w", err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(cipherByte), nil
|
||||
}
|
||||
|
||||
// 敏感信息解密
|
||||
func (c *ClientV3) V3DecryptText(cipherText string) (text string, err error) {
|
||||
cipherByte, _ := base64.StdEncoding.DecodeString(cipherText)
|
||||
textByte, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, c.privateKey, cipherByte, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("rsa.DecryptOAEP:%w", err)
|
||||
}
|
||||
return string(textByte), nil
|
||||
}
|
||||
|
||||
// 敏感参数信息加密
|
||||
// wxPublicKeyContent:微信平台证书内容
|
||||
func V3EncryptText(text string, wxPublicKeyContent []byte) (cipherText string, err error) {
|
||||
publicKey, err := xpem.DecodePublicKey(wxPublicKeyContent)
|
||||
if err != nil {
|
||||
return gopay.NULL, err
|
||||
}
|
||||
cipherByte, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, publicKey, []byte(text), nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("rsa.EncryptOAEP:%w", err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(cipherByte), nil
|
||||
}
|
||||
|
||||
// 敏感参数信息解密
|
||||
// privateKeyContent:私钥 apiclient_key.pem 读取后的字符串内容
|
||||
func V3DecryptText(cipherText string, privateKeyContent []byte) (text string, err error) {
|
||||
privateKey, err := xpem.DecodePrivateKey(privateKeyContent)
|
||||
if err != nil {
|
||||
return gopay.NULL, err
|
||||
}
|
||||
cipherByte, _ := base64.StdEncoding.DecodeString(cipherText)
|
||||
textByte, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, privateKey, cipherByte, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("rsa.DecryptOAEP:%w", err)
|
||||
}
|
||||
return string(textByte), nil
|
||||
}
|
||||
|
||||
// 解密 普通支付 回调中的加密信息
|
||||
func V3DecryptNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptResult, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
result = &V3DecryptResult{}
|
||||
if err = json.Unmarshal(decrypt, result); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 解密 服务商支付 回调中的加密信息
|
||||
func V3DecryptPartnerNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptPartnerResult, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
result = &V3DecryptPartnerResult{}
|
||||
if err = json.Unmarshal(decrypt, result); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 解密 普通退款 回调中的加密信息
|
||||
func V3DecryptRefundNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptRefundResult, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
result = &V3DecryptRefundResult{}
|
||||
if err = json.Unmarshal(decrypt, result); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 解密 服务商退款 回调中的加密信息
|
||||
func V3DecryptPartnerRefundNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptPartnerRefundResult, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
result = &V3DecryptPartnerRefundResult{}
|
||||
if err = json.Unmarshal(decrypt, result); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 解密 合单支付 回调中的加密信息
|
||||
func V3DecryptCombineNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptCombineResult, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
result = &V3DecryptCombineResult{}
|
||||
if err = json.Unmarshal(decrypt, result); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 解密分账动账回调中的加密信息
|
||||
func V3DecryptProfitShareNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptProfitShareResult, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
result = &V3DecryptProfitShareResult{}
|
||||
if err = json.Unmarshal(decrypt, result); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 解密 支付分 回调中的加密信息
|
||||
func V3DecryptScoreNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptScoreResult, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
result = &V3DecryptScoreResult{}
|
||||
if err = json.Unmarshal(decrypt, result); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 解密商家券回调中的加密信息
|
||||
func V3DecryptBusifavorNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptBusifavorResult, err error) {
|
||||
cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext)
|
||||
decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err)
|
||||
}
|
||||
result = &V3DecryptBusifavorResult{}
|
||||
if err = json.Unmarshal(decrypt, result); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 点金计划管理API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_5_1.shtml
|
||||
func (c *ClientV3) V3GoldPlanManage(ctx context.Context, bm gopay.BodyMap) (wxRsp *GoldPlanManageRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3GoldPlanManage, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3GoldPlanManage, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &GoldPlanManageRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(GoldPlanManage)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商家小票管理API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_5_2.shtml
|
||||
func (c *ClientV3) V3GoldPlanBillManage(ctx context.Context, bm gopay.BodyMap) (wxRsp *GoldPlanManageRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3GoldPlanBillManage, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3GoldPlanBillManage, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &GoldPlanManageRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(GoldPlanManage)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 同业过滤标签管理API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_5_3.shtml
|
||||
func (c *ClientV3) V3GoldPlanFilterManage(ctx context.Context, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3GoldPlanFilterManage, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3GoldPlanFilterManage, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 开通广告展示API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_5_4.shtml
|
||||
func (c *ClientV3) V3GoldPlanOpenAdShow(ctx context.Context, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPATCH, v3GoldPlanOpenAdShow, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPatch(ctx, bm, v3GoldPlanOpenAdShow, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 关闭广告展示API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_5_5.shtml
|
||||
func (c *ClientV3) V3GoldPlanCloseAdShow(ctx context.Context, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPATCH, v3GoldPlanCloseAdShow, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3GoldPlanCloseAdShow, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package wechat
|
||||
|
||||
// 支付有礼
|
||||
+456
@@ -0,0 +1,456 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 创建商家券
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_1.shtml
|
||||
func (c *ClientV3) V3BusiFavorBatchCreate(ctx context.Context, bm gopay.BodyMap) (wxRsp *BusiFavorCreateRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusiFavorBatchCreate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusiFavorBatchCreate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorCreateRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorBatchCreate)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询商家券详情
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_2.shtml
|
||||
func (c *ClientV3) V3BusiFavorBatchDetail(ctx context.Context, stockId string) (wxRsp *BusiFavorBatchDetailRsp, err error) {
|
||||
uri := fmt.Sprintf(v3BusiFavorBatchDetail, stockId)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorBatchDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorBatchDetail)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 核销用户券
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_3.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_3.shtml
|
||||
func (c *ClientV3) V3BusiFavorUse(ctx context.Context, bm gopay.BodyMap) (wxRsp *BusiFavorUseRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusiFavorUse, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusiFavorUse, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorUseRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorUse)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 根据过滤条件查询用户券
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_4.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_4.shtml
|
||||
func (c *ClientV3) V3BusiFavorUserCoupons(ctx context.Context, openid string, bm gopay.BodyMap) (wxRsp *BusiFavorUserCouponsRsp, err error) {
|
||||
uri := fmt.Sprintf(v3BusiFavorUserCoupons, openid) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorUserCouponsRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorUserCoupons)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询用户单张券详情
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_5.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_5.shtml
|
||||
func (c *ClientV3) V3BusiFavorUserCouponDetail(ctx context.Context, openid, couponCode, appid string) (wxRsp *BusiFavorUserCouponDetailRsp, err error) {
|
||||
uri := fmt.Sprintf(v3BusiFavorUserCouponDetail, openid, couponCode, appid)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorUserCouponDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiUserCoupon)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 上传预存code
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_6.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_6.shtml
|
||||
func (c *ClientV3) V3BusiFavorCodeUpload(ctx context.Context, stockId string, bm gopay.BodyMap) (wxRsp *BusiFavorCodeUploadRsp, err error) {
|
||||
url := fmt.Sprintf(v3BusiFavorCodeUpload, stockId)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorCodeUploadRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorCodeUpload)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 设置商家券事件通知地址
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_7.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_7.shtml
|
||||
func (c *ClientV3) V3BusiFavorCallbackUrlSet(ctx context.Context, bm gopay.BodyMap) (wxRsp *BusiFavorCallbackUrlSetRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusiFavorCallbackUrlSet, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusiFavorCallbackUrlSet, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorCallbackUrlSetRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorCallbackUrlSet)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询商家券事件通知地址
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_8.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_8.shtml
|
||||
func (c *ClientV3) V3BusiFavorCallbackUrl(ctx context.Context, mchid string) (wxRsp *BusiFavorCallbackUrlRsp, err error) {
|
||||
uri := v3BusiFavorCallbackUrl + "?mchid=" + mchid
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorCallbackUrlRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorCallbackUrl)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 关联订单信息
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_9.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_9.shtml
|
||||
func (c *ClientV3) V3BusiFavorAssociate(ctx context.Context, bm gopay.BodyMap) (wxRsp *BusiFavorAssociateRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusiFavorAssociate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusiFavorAssociate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorAssociateRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorAssociate)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 取消关联订单信息
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_10.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_10.shtml
|
||||
func (c *ClientV3) V3BusiFavorDisassociate(ctx context.Context, bm gopay.BodyMap) (wxRsp *BusiFavorDisassociateRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusiFavorDisassociate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusiFavorDisassociate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorDisassociateRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorDisassociate)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 修改批次预算
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_11.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_11.shtml
|
||||
func (c *ClientV3) V3BusiFavorBatchUpdate(ctx context.Context, stockId string, bm gopay.BodyMap) (wxRsp *BusiFavorBatchUpdateRsp, err error) {
|
||||
url := fmt.Sprintf(v3BusiFavorBatchUpdate, stockId)
|
||||
authorization, err := c.authorization(MethodPATCH, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPatch(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorBatchUpdateRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorBatchUpdate)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 修改商家券基本信息
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_12.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_12.shtml
|
||||
func (c *ClientV3) V3BusiFavorInfoUpdate(ctx context.Context, stockId string, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
url := fmt.Sprintf(v3BusiFavorInfoUpdate, stockId)
|
||||
authorization, err := c.authorization(MethodPATCH, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPatch(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 发放消费卡
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_6_1.shtml
|
||||
func (c *ClientV3) V3BusiFavorSend(ctx context.Context, cardId string, bm gopay.BodyMap) (wxRsp *BusiFavorSendRsp, err error) {
|
||||
url := fmt.Sprintf(v3BusiFavorSend, cardId)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorSendRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorSend)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 申请退券
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_13.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_13.shtml
|
||||
func (c *ClientV3) V3BusiFavorReturn(ctx context.Context, bm gopay.BodyMap) (wxRsp *BusiFavorReturnRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusiFavorReturn, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusiFavorReturn, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorReturnRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorReturn)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 使券失效
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_14.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_14.shtml
|
||||
func (c *ClientV3) V3BusiFavorDeactivate(ctx context.Context, bm gopay.BodyMap) (wxRsp *BusiFavorDeactivateRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusiFavorDeactivate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusiFavorDeactivate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorDeactivateRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorDeactivate)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 营销补差付款
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_16.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_16.shtml
|
||||
func (c *ClientV3) V3BusiFavorSubsidyPay(ctx context.Context, bm gopay.BodyMap) (wxRsp *BusiFavorSubsidyPayRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3BusiFavorSubsidyPay, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3BusiFavorSubsidyPay, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorSubsidyPayRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorSubsidyPay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询营销补差付款单详情
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_2_18.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_2_18.shtml
|
||||
func (c *ClientV3) V3BusiFavorSubsidyPayDetail(ctx context.Context, subsidyReceiptId string) (wxRsp *BusiFavorSubsidyPayDetailRsp, err error) {
|
||||
url := fmt.Sprintf(v3BusiFavorSubsidyPayDetail, subsidyReceiptId)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &BusiFavorSubsidyPayDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(BusiFavorSubsidyPay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+399
@@ -0,0 +1,399 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// 创建代金券批次
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_1.shtml
|
||||
func (c *ClientV3) V3FavorBatchCreate(ctx context.Context, bm gopay.BodyMap) (wxRsp *FavorBatchCreateRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3FavorBatchCreate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3FavorBatchCreate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorBatchCreateRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorBatchCreate)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 发放代金券批次
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_2.shtml
|
||||
func (c *ClientV3) V3FavorBatchGrant(ctx context.Context, openid string, bm gopay.BodyMap) (wxRsp *FavorBatchGrantRsp, err error) {
|
||||
url := fmt.Sprintf(v3FavorBatchGrant, openid)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorBatchGrantRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorBatchGrant)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 激活代金券批次
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_3.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_3.shtml
|
||||
func (c *ClientV3) V3FavorBatchStart(ctx context.Context, stockId, stockCreatorMchid string) (wxRsp *FavorBatchStartRsp, err error) {
|
||||
url := fmt.Sprintf(v3FavorBatchStart, stockId)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("stock_creator_mchid", stockCreatorMchid)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorBatchStartRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorBatchStart)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 条件查询批次列表
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_4.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_4.shtml
|
||||
func (c *ClientV3) V3FavorBatchList(ctx context.Context, bm gopay.BodyMap) (wxRsp *FavorBatchListRsp, err error) {
|
||||
uri := v3FavorBatchList + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorBatchListRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorBatchList)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询批次详情
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_5.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_5.shtml
|
||||
func (c *ClientV3) V3FavorBatchDetail(ctx context.Context, stockId, stockCreatorMchid string) (wxRsp *FavorBatchDetailRsp, err error) {
|
||||
uri := fmt.Sprintf(v3FavorBatchDetail, stockId) + "?stock_creator_mchid=" + stockCreatorMchid
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorBatchDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorBatch)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询代金券详情
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_6.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_6.shtml
|
||||
func (c *ClientV3) V3FavorDetail(ctx context.Context, appid, couponId, openid string) (wxRsp *FavorDetailRsp, err error) {
|
||||
uri := fmt.Sprintf(v3FavorDetail, openid, couponId) + "?appid=" + appid
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorDetail)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询代金券可用商户
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_7.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_7.shtml
|
||||
func (c *ClientV3) V3FavorMerchant(ctx context.Context, stockId, stockCreatorMchid string, limit, offset int) (wxRsp *FavorMerchantRsp, err error) {
|
||||
if limit == 0 {
|
||||
limit = 20
|
||||
}
|
||||
uri := fmt.Sprintf(v3FavorMerchant, stockId) + "?stock_creator_mchid=" + stockCreatorMchid + "&limit=" + util.Int2String(limit) + "&offset=" + util.Int2String(offset)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorMerchantRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorMerchant)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询代金券可用单品
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_8.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_8.shtml
|
||||
func (c *ClientV3) V3FavorItems(ctx context.Context, stockId, stockCreatorMchid string, limit, offset int) (wxRsp *FavorItemsRsp, err error) {
|
||||
if limit == 0 {
|
||||
limit = 20
|
||||
}
|
||||
uri := fmt.Sprintf(v3FavorItems, stockId) + "?stock_creator_mchid=" + stockCreatorMchid + "&limit=" + util.Int2String(limit) + "&offset=" + util.Int2String(offset)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorItemsRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorItems)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 根据商户号查用户的券
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_9.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_9.shtml
|
||||
func (c *ClientV3) V3FavorUserCoupons(ctx context.Context, openid string, bm gopay.BodyMap) (wxRsp *FavorUserCouponsRsp, err error) {
|
||||
uri := fmt.Sprintf(v3FavorUserCoupons, openid) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorUserCouponsRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorUserCoupons)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 下载批次核销明细
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_10.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_10.shtml
|
||||
func (c *ClientV3) V3FavorUseFlowDownload(ctx context.Context, stockId string) (wxRsp *FavorUseFlowDownloadRsp, err error) {
|
||||
url := fmt.Sprintf(v3FavorUseFlowDownload, stockId)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorUseFlowDownloadRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorFlowDownload)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 下载批次退款明细
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_11.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_11.shtml
|
||||
func (c *ClientV3) V3FavorRefundFlowDownload(ctx context.Context, stockId string) (wxRsp *FavorRefundFlowDownloadRsp, err error) {
|
||||
url := fmt.Sprintf(v3FavorRefundFlowDownload, stockId)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorRefundFlowDownloadRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorFlowDownload)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 设置消息通知地址
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_12.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_12.shtml
|
||||
func (c *ClientV3) V3FavorCallbackUrlSet(ctx context.Context, bm gopay.BodyMap) (wxRsp *FavorCallbackUrlSetRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3FavorCallbackUrlSet, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3FavorCallbackUrlSet, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorCallbackUrlSetRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorCallbackUrl)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 暂停代金券批次
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_13.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_13.shtml
|
||||
func (c *ClientV3) V3FavorBatchPause(ctx context.Context, stockId, stockCreatorMchid string) (wxRsp *FavorBatchPauseRsp, err error) {
|
||||
url := fmt.Sprintf(v3FavorBatchPause, stockId)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("stock_creator_mchid", stockCreatorMchid)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorBatchPauseRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorBatchPause)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 重启代金券批次
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_14.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_1_14.shtml
|
||||
func (c *ClientV3) V3FavorBatchRestart(ctx context.Context, stockId, stockCreatorMchid string) (wxRsp *FavorBatchRestartRsp, err error) {
|
||||
url := fmt.Sprintf(v3FavorBatchRestart, stockId)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("stock_creator_mchid", stockCreatorMchid)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &FavorBatchRestartRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(FavorBatchRestart)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// 图片上传(营销专用)
|
||||
// 注意:图片不能超过2MB
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_0_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_0_1.shtml
|
||||
func (c *ClientV3) V3FavorMediaUploadImage(ctx context.Context, fileName, fileSha256 string, img *util.File) (wxRsp *MarketMediaUploadRsp, err error) {
|
||||
bmFile := make(gopay.BodyMap)
|
||||
bmFile.Set("filename", fileName).Set("sha256", fileSha256)
|
||||
authorization, err := c.authorization(MethodPost, v3FavorMediaUploadImage, bmFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.SetBodyMap("meta", func(bm gopay.BodyMap) {
|
||||
bm.Set("filename", fileName).Set("sha256", fileSha256)
|
||||
}).SetFormFile("file", img)
|
||||
res, si, bs, err := c.doProdPostFile(ctx, bm, v3FavorMediaUploadImage, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &MarketMediaUploadRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(MarketMediaUpload)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 建立合作关系
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_5_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_5_1.shtml
|
||||
func (c *ClientV3) V3PartnershipsBuild(ctx context.Context, idempotencyKey string, bm gopay.BodyMap) (wxRsp *PartnershipsBuildRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3PartnershipsBuild, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPostWithHeader(ctx, map[string]string{"Idempotency-Key": idempotencyKey}, bm, v3PartnershipsBuild, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PartnershipsBuildRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnershipsBuild)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 终止合作关系
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_5_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_5_2.shtml
|
||||
func (c *ClientV3) V3PartnershipsTerminate(ctx context.Context, idempotencyKey string, bm gopay.BodyMap) (wxRsp *PartnershipsTerminateRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3PartnershipsTerminate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPostWithHeader(ctx, map[string]string{"Idempotency-Key": idempotencyKey}, bm, v3PartnershipsTerminate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PartnershipsTerminateRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnershipsTerminate)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询合作关系列表
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_5_3.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_5_3.shtml
|
||||
func (c *ClientV3) V3PartnershipsList(ctx context.Context, bm gopay.BodyMap) (wxRsp *PartnershipsListRsp, err error) {
|
||||
uri := v3PartnershipsList + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PartnershipsListRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnershipsList)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// 图片上传API
|
||||
// 注意:图片不能超过2MB
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter2_1_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter2_1_1.shtml
|
||||
func (c *ClientV3) V3MediaUploadImage(ctx context.Context, fileName, fileSha256 string, img *util.File) (wxRsp *MediaUploadRsp, err error) {
|
||||
bmFile := make(gopay.BodyMap)
|
||||
bmFile.Set("filename", fileName).Set("sha256", fileSha256)
|
||||
authorization, err := c.authorization(MethodPost, v3MediaUploadImage, bmFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.SetBodyMap("meta", func(bm gopay.BodyMap) {
|
||||
bm.Set("filename", fileName).Set("sha256", fileSha256)
|
||||
}).SetFormFile("file", img)
|
||||
res, si, bs, err := c.doProdPostFile(ctx, bm, v3MediaUploadImage, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &MediaUploadRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(MediaUpload)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 视频上传API
|
||||
// 注意:媒体视频只支持avi、wmv、mpeg、mp4、mov、mkv、flv、f4v、m4v、rmvb格式,文件大小不能超过5M。
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter2_1_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter2_1_2.shtml
|
||||
func (c *ClientV3) V3MediaUploadVideo(ctx context.Context, fileName, fileSha256 string, img *util.File) (wxRsp *MediaUploadRsp, err error) {
|
||||
bmFile := make(gopay.BodyMap)
|
||||
bmFile.Set("filename", fileName).Set("sha256", fileSha256)
|
||||
authorization, err := c.authorization(MethodPost, v3MediaUploadVideo, bmFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.SetBodyMap("meta", func(bm gopay.BodyMap) {
|
||||
bm.Set("filename", fileName).Set("sha256", fileSha256)
|
||||
}).SetFormFile("file", img)
|
||||
res, si, bs, err := c.doProdPostFile(ctx, bm, v3MediaUploadVideo, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &MediaUploadRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(MediaUpload)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 查询特约商户账户实时余额、查询二级商户账户实时余额
|
||||
// Code = 0 is success
|
||||
// 注意:服务商时,bm参数传 nil
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter5_1.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_1.shtml
|
||||
func (c *ClientV3) V3EcommerceBalance(ctx context.Context, subMchid string, bm gopay.BodyMap) (*EcommerceBalanceRsp, error) {
|
||||
url := fmt.Sprintf(v3EcommerceBalance, subMchid) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceBalanceRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceBalance)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询二级商户账户日终余额
|
||||
// date示例值:2019-08-17
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_2.shtml
|
||||
func (c *ClientV3) V3EcommerceDayBalance(ctx context.Context, subMchid, date string) (*EcommerceBalanceRsp, error) {
|
||||
uri := fmt.Sprintf(v3EcommerceDayBalance, subMchid) + "?date=" + date
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceBalanceRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceBalance)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询账户实时余额
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter5_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter5_2.shtml
|
||||
// 电商平台:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_3.shtml
|
||||
func (c *ClientV3) V3MerchantBalance(ctx context.Context, accountType string) (*MerchantBalanceRsp, error) {
|
||||
url := fmt.Sprintf(v3MerchantBalance, accountType)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &MerchantBalanceRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(MerchantBalance)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询账户日终余额
|
||||
// date示例值:2019-08-17
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter5_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter5_3.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_4.shtml
|
||||
func (c *ClientV3) V3MerchantDayBalance(ctx context.Context, accountType, date string) (*MerchantBalanceRsp, error) {
|
||||
uri := fmt.Sprintf(v3MerchantDayBalance, accountType) + "?date=" + date
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &MerchantBalanceRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(MerchantBalance)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 特约商户银行来账查询API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_6.shtml
|
||||
func (c *ClientV3) V3EcommerceIncomeRecord(ctx context.Context, bm gopay.BodyMap) (*PartnerIncomeRecordRsp, error) {
|
||||
uri := v3EcommerceIncomeRecord + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &PartnerIncomeRecordRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnerIncomeRecord)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商户/服务商银行来账查询API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_7.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_7.shtml
|
||||
func (c *ClientV3) V3MerchantIncomeRecord(ctx context.Context, bm gopay.BodyMap) (*MerchantIncomeRecordRsp, error) {
|
||||
uri := v3MerchantIncomeRecord + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &MerchantIncomeRecordRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(MerchantIncomeRecord)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+2743
File diff suppressed because it is too large
Load Diff
+328
@@ -0,0 +1,328 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/xlog"
|
||||
)
|
||||
|
||||
type Resource struct {
|
||||
OriginalType string `json:"original_type"`
|
||||
Algorithm string `json:"algorithm"`
|
||||
Ciphertext string `json:"ciphertext"`
|
||||
AssociatedData string `json:"associated_data"`
|
||||
Nonce string `json:"nonce"`
|
||||
}
|
||||
|
||||
type V3DecryptResult struct {
|
||||
Appid string `json:"appid"`
|
||||
Mchid string `json:"mchid"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
TransactionId string `json:"transaction_id"`
|
||||
TradeType string `json:"trade_type"`
|
||||
TradeState string `json:"trade_state"`
|
||||
TradeStateDesc string `json:"trade_state_desc"`
|
||||
BankType string `json:"bank_type"`
|
||||
Attach string `json:"attach"`
|
||||
SuccessTime string `json:"success_time"`
|
||||
Payer *Payer `json:"payer"`
|
||||
Amount *Amount `json:"amount"`
|
||||
SceneInfo *SceneInfo `json:"scene_info"`
|
||||
PromotionDetail []*PromotionDetail `json:"promotion_detail"`
|
||||
}
|
||||
|
||||
type V3DecryptPartnerResult struct {
|
||||
SpAppid string `json:"sp_appid"`
|
||||
SpMchid string `json:"sp_mchid"`
|
||||
SubAppid string `json:"sub_appid"`
|
||||
SubMchid string `json:"sub_mchid"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
TransactionId string `json:"transaction_id"`
|
||||
TradeType string `json:"trade_type"`
|
||||
TradeState string `json:"trade_state"`
|
||||
TradeStateDesc string `json:"trade_state_desc"`
|
||||
BankType string `json:"bank_type"`
|
||||
Attach string `json:"attach"`
|
||||
SuccessTime string `json:"success_time"`
|
||||
Payer *PartnerPayer `json:"payer"`
|
||||
Amount *Amount `json:"amount"`
|
||||
SceneInfo *SceneInfo `json:"scene_info"`
|
||||
PromotionDetail []*PromotionDetail `json:"promotion_detail"`
|
||||
}
|
||||
|
||||
type V3DecryptRefundResult struct {
|
||||
Mchid string `json:"mchid"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
TransactionId string `json:"transaction_id"`
|
||||
OutRefundNo string `json:"out_refund_no"`
|
||||
RefundId string `json:"refund_id"`
|
||||
RefundStatus string `json:"refund_status"`
|
||||
SuccessTime string `json:"success_time"`
|
||||
UserReceivedAccount string `json:"user_received_account"`
|
||||
Amount *RefundAmount `json:"amount"`
|
||||
}
|
||||
|
||||
type V3DecryptPartnerRefundResult struct {
|
||||
SpMchid string `json:"sp_mchid"`
|
||||
SubMchid string `json:"sub_mchid"`
|
||||
OutTradeNo string `json:"out_trade_no"`
|
||||
TransactionId string `json:"transaction_id"`
|
||||
OutRefundNo string `json:"out_refund_no"`
|
||||
RefundId string `json:"refund_id"`
|
||||
RefundStatus string `json:"refund_status"`
|
||||
SuccessTime string `json:"success_time"`
|
||||
UserReceivedAccount string `json:"user_received_account"`
|
||||
Amount *RefundAmount `json:"amount"`
|
||||
}
|
||||
|
||||
type V3DecryptCombineResult struct {
|
||||
CombineAppid string `json:"combine_appid"`
|
||||
CombineMchid string `json:"combine_mchid"`
|
||||
CombineOutTradeNo string `json:"combine_out_trade_no"`
|
||||
SceneInfo *SceneInfo `json:"scene_info"`
|
||||
SubOrders []*SubOrders `json:"sub_orders"` // 最多支持子单条数:50
|
||||
CombinePayerInfo *Payer `json:"combine_payer_info"` // 支付者信息
|
||||
}
|
||||
|
||||
type V3DecryptScoreResult struct {
|
||||
Appid string `json:"appid"`
|
||||
Mchid string `json:"mchid"`
|
||||
OutOrderNo string `json:"out_order_no"`
|
||||
ServiceId string `json:"service_id"`
|
||||
Openid string `json:"openid"`
|
||||
State string `json:"state"`
|
||||
StateDescription string `json:"state_description"`
|
||||
TotalAmount int `json:"total_amount"`
|
||||
ServiceIntroduction string `json:"service_introduction"`
|
||||
PostPayments []*PostPayments `json:"post_payments"`
|
||||
PostDiscounts []*PostDiscounts `json:"post_discounts"`
|
||||
RiskFund *RiskFund `json:"risk_fund"`
|
||||
TimeRange *TimeRange `json:"time_range"`
|
||||
Location *Location `json:"location"`
|
||||
Attach string `json:"attach"`
|
||||
NotifyUrl string `json:"notify_url"`
|
||||
OrderId string `json:"order_id"`
|
||||
NeedCollection bool `json:"need_collection"`
|
||||
Collection *Collection `json:"collection"`
|
||||
}
|
||||
|
||||
type V3DecryptProfitShareResult struct {
|
||||
SpMchid string `json:"sp_mchid"` // 服务商商户号
|
||||
SubMchid string `json:"sub_mchid"` // 子商户号
|
||||
TransactionId string `json:"transaction_id"` // 微信订单号
|
||||
OrderId string `json:"order_id"` // 微信分账/回退单号
|
||||
OutOrderNo string `json:"out_order_no"` // 商户分账/回退单号
|
||||
Receiver *Receiver `json:"receiver"`
|
||||
SuccessTime string `json:"success_time"` // 成功时间
|
||||
}
|
||||
|
||||
type Receiver struct {
|
||||
Type string `json:"type"` // 分账接收方类型
|
||||
Account string `json:"account"` // 分账接收方账号
|
||||
Amount int `json:"amount"` // 分账动账金额
|
||||
Description string `json:"description"` // 分账/回退描述
|
||||
}
|
||||
|
||||
type V3DecryptBusifavorResult struct {
|
||||
EventType string `json:"event_type"` // 事件类型
|
||||
CouponCode string `json:"coupon_code"` // 券code
|
||||
StockId string `json:"stock_id"` // 批次号
|
||||
SendTime string `json:"send_time"` // 发放时间
|
||||
Openid string `json:"openid"` // 用户标识
|
||||
Unionid string `json:"unionid"` // 用户统一标识
|
||||
SendChannel string `json:"send_channel"` // 发放渠道
|
||||
SendMerchant string `json:"send_merchant"` // 发券商户号
|
||||
AttachInfo *BusifavorAttachInfo `json:"attach_info"` // 发券附加信息
|
||||
}
|
||||
|
||||
type BusifavorAttachInfo struct {
|
||||
TransactionId string `json:"transaction_id"` // 交易订单编号
|
||||
ActCode string `json:"act_code"` // 支付有礼活动编号/营销馆活动ID
|
||||
HallCode string `json:"hall_code"` // 营销馆ID
|
||||
HallBelongMchID int `json:"hall_belong_mch_id"` // 营销馆所属商户号
|
||||
CardID string `json:"card_id"` // 会员卡ID
|
||||
Code string `json:"code"` // 会员卡code
|
||||
ActivityID string `json:"activity_id"` // 会员活动ID
|
||||
}
|
||||
|
||||
type V3NotifyReq struct {
|
||||
Id string `json:"id"`
|
||||
CreateTime string `json:"create_time"`
|
||||
ResourceType string `json:"resource_type"`
|
||||
EventType string `json:"event_type"`
|
||||
Summary string `json:"summary"`
|
||||
Resource *Resource `json:"resource"`
|
||||
SignInfo *SignInfo `json:"-"`
|
||||
}
|
||||
|
||||
type V3NotifyRsp struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// 解析微信回调请求的参数到 V3NotifyReq 结构体
|
||||
func V3ParseNotify(req *http.Request) (notifyReq *V3NotifyReq, err error) {
|
||||
bs, err := ioutil.ReadAll(io.LimitReader(req.Body, int64(3<<20))) // default 3MB change the size you want;
|
||||
defer req.Body.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read request body error:%w", err)
|
||||
}
|
||||
si := &SignInfo{
|
||||
HeaderTimestamp: req.Header.Get(HeaderTimestamp),
|
||||
HeaderNonce: req.Header.Get(HeaderNonce),
|
||||
HeaderSignature: req.Header.Get(HeaderSignature),
|
||||
HeaderSerial: req.Header.Get(HeaderSerial),
|
||||
SignBody: string(bs),
|
||||
}
|
||||
notifyReq = &V3NotifyReq{SignInfo: si}
|
||||
if err = json.Unmarshal(bs, notifyReq); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s, %+v):%w", string(bs), notifyReq, err)
|
||||
}
|
||||
return notifyReq, nil
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
// 推荐使用 VerifySignByPK()
|
||||
func (v *V3NotifyReq) VerifySign(wxPkContent string) (err error) {
|
||||
if v.SignInfo != nil {
|
||||
return V3VerifySign(v.SignInfo.HeaderTimestamp, v.SignInfo.HeaderNonce, v.SignInfo.SignBody, v.SignInfo.HeaderSignature, wxPkContent)
|
||||
}
|
||||
return errors.New("verify notify sign, bug SignInfo is nil")
|
||||
}
|
||||
|
||||
// 异步通知验签
|
||||
// wxPublicKey:微信平台证书公钥内容,通过 client.WxPublicKey() 获取
|
||||
func (v *V3NotifyReq) VerifySignByPK(wxPublicKey *rsa.PublicKey) (err error) {
|
||||
if v.SignInfo != nil {
|
||||
return V3VerifySignByPK(v.SignInfo.HeaderTimestamp, v.SignInfo.HeaderNonce, v.SignInfo.SignBody, v.SignInfo.HeaderSignature, wxPublicKey)
|
||||
}
|
||||
return errors.New("verify notify sign, bug SignInfo is nil")
|
||||
}
|
||||
|
||||
// 解密 普通支付 回调中的加密信息
|
||||
func (v *V3NotifyReq) DecryptCipherText(apiV3Key string) (result *V3DecryptResult, err error) {
|
||||
if v.Resource != nil {
|
||||
result, err = V3DecryptNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key)
|
||||
if err != nil {
|
||||
bytes, _ := json.Marshal(v)
|
||||
return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("notify data Resource is nil")
|
||||
}
|
||||
|
||||
// 解密 服务商支付 回调中的加密信息
|
||||
func (v *V3NotifyReq) DecryptPartnerCipherText(apiV3Key string) (result *V3DecryptPartnerResult, err error) {
|
||||
if v.Resource != nil {
|
||||
result, err = V3DecryptPartnerNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key)
|
||||
if err != nil {
|
||||
bytes, _ := json.Marshal(v)
|
||||
return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("notify data Resource is nil")
|
||||
}
|
||||
|
||||
// 解密 普通退款 回调中的加密信息
|
||||
func (v *V3NotifyReq) DecryptRefundCipherText(apiV3Key string) (result *V3DecryptRefundResult, err error) {
|
||||
if v.Resource != nil {
|
||||
result, err = V3DecryptRefundNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key)
|
||||
if err != nil {
|
||||
bytes, _ := json.Marshal(v)
|
||||
return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("notify data Resource is nil")
|
||||
}
|
||||
|
||||
// 解密 服务商退款 回调中的加密信息
|
||||
func (v *V3NotifyReq) DecryptPartnerRefundCipherText(apiV3Key string) (result *V3DecryptPartnerRefundResult, err error) {
|
||||
if v.Resource != nil {
|
||||
result, err = V3DecryptPartnerRefundNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key)
|
||||
if err != nil {
|
||||
bytes, _ := json.Marshal(v)
|
||||
return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("notify data Resource is nil")
|
||||
}
|
||||
|
||||
// 解密 合单支付 回调中的加密信息
|
||||
func (v *V3NotifyReq) DecryptCombineCipherText(apiV3Key string) (result *V3DecryptCombineResult, err error) {
|
||||
if v.Resource != nil {
|
||||
result, err = V3DecryptCombineNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key)
|
||||
if err != nil {
|
||||
bytes, _ := json.Marshal(v)
|
||||
return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("notify data Resource is nil")
|
||||
}
|
||||
|
||||
// 解密 支付分 回调中的加密信息
|
||||
func (v *V3NotifyReq) DecryptScoreCipherText(apiV3Key string) (result *V3DecryptScoreResult, err error) {
|
||||
if v.Resource != nil {
|
||||
result, err = V3DecryptScoreNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key)
|
||||
if err != nil {
|
||||
bytes, _ := json.Marshal(v)
|
||||
return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("notify data Resource is nil")
|
||||
}
|
||||
|
||||
// 解密分账动账回调中的加密信息
|
||||
func (v *V3NotifyReq) DecryptProfitShareCipherText(apiV3Key string) (result *V3DecryptProfitShareResult, err error) {
|
||||
if v.Resource != nil {
|
||||
result, err = V3DecryptProfitShareNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key)
|
||||
if err != nil {
|
||||
bytes, _ := json.Marshal(v)
|
||||
return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("notify data Resource is nil")
|
||||
}
|
||||
|
||||
// 解密商家券回调中的加密信息
|
||||
func (v *V3NotifyReq) DecryptBusifavorCipherText(apiV3Key string) (result *V3DecryptBusifavorResult, err error) {
|
||||
if v.Resource != nil {
|
||||
result, err = V3DecryptBusifavorNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key)
|
||||
if err != nil {
|
||||
bytes, _ := json.Marshal(v)
|
||||
return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, errors.New("notify data Resource is nil")
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
// 暂时不推荐此方法,请使用 wechat.V3ParseNotify()
|
||||
// 解析微信回调请求的参数到 gopay.BodyMap
|
||||
func V3ParseNotifyToBodyMap(req *http.Request) (bm gopay.BodyMap, err error) {
|
||||
bs, err := ioutil.ReadAll(io.LimitReader(req.Body, int64(3<<20))) // default 3MB change the size you want;
|
||||
defer req.Body.Close()
|
||||
if err != nil {
|
||||
xlog.Error("err:", err)
|
||||
return
|
||||
}
|
||||
bm = make(gopay.BodyMap)
|
||||
if err = json.Unmarshal(bs, &bm); err != nil {
|
||||
return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err)
|
||||
}
|
||||
return bm, nil
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// APP下单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml
|
||||
func (c *ClientV3) V3TransactionApp(ctx context.Context, bm gopay.BodyMap) (wxRsp *PrepayRsp, err error) {
|
||||
if bm.GetString("mchid") == util.NULL {
|
||||
bm.Set("mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3ApiApp, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ApiApp, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PrepayRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Prepay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// JSAPI/小程序下单API
|
||||
// Code = 0 is success
|
||||
// 商户JSAPI文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
|
||||
// 商户小程序文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml
|
||||
func (c *ClientV3) V3TransactionJsapi(ctx context.Context, bm gopay.BodyMap) (wxRsp *PrepayRsp, err error) {
|
||||
if bm.GetString("mchid") == util.NULL {
|
||||
bm.Set("mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3ApiJsapi, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ApiJsapi, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PrepayRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Prepay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// Native下单API
|
||||
// Code = 0 is success
|
||||
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_1.shtml
|
||||
func (c *ClientV3) V3TransactionNative(ctx context.Context, bm gopay.BodyMap) (wxRsp *NativeRsp, err error) {
|
||||
if bm.GetString("mchid") == util.NULL {
|
||||
bm.Set("mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3ApiNative, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ApiNative, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &NativeRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Native)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// H5下单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_1.shtml
|
||||
func (c *ClientV3) V3TransactionH5(ctx context.Context, bm gopay.BodyMap) (wxRsp *H5Rsp, err error) {
|
||||
if bm.GetString("mchid") == util.NULL {
|
||||
bm.Set("mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3ApiH5, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ApiH5, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &H5Rsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(H5Url)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
|
||||
func (c *ClientV3) V3TransactionQueryOrder(ctx context.Context, orderNoType OrderNoType, orderNo string) (wxRsp *QueryOrderRsp, err error) {
|
||||
var uri string
|
||||
switch orderNoType {
|
||||
case TransactionId:
|
||||
uri = fmt.Sprintf(v3ApiQueryOrderTransactionId, orderNo) + "?mchid=" + c.Mchid
|
||||
case OutTradeNo:
|
||||
uri = fmt.Sprintf(v3ApiQueryOrderOutTradeNo, orderNo) + "?mchid=" + c.Mchid
|
||||
default:
|
||||
return nil, errors.New("unsupported order number type")
|
||||
}
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &QueryOrderRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(QueryOrder)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 关闭订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_3.shtml
|
||||
func (c *ClientV3) V3TransactionCloseOrder(ctx context.Context, tradeNo string) (wxRsp *CloseOrderRsp, err error) {
|
||||
url := fmt.Sprintf(v3ApiCloseOrder, tradeNo)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("mchid", c.Mchid)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &CloseOrderRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// 合单APP下单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_1.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_3_1.shtml
|
||||
func (c *ClientV3) V3CombineTransactionApp(ctx context.Context, bm gopay.BodyMap) (wxRsp *PrepayRsp, err error) {
|
||||
if bm.GetString("combine_mchid") == util.NULL {
|
||||
bm.Set("combine_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3CombinePayApp, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3CombinePayApp, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PrepayRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Prepay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 合单JSAPI/小程序下单API
|
||||
// Code = 0 is success
|
||||
// 商户JSAPI文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_3.shtml
|
||||
// 商户小程序文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_4.shtml
|
||||
// 服务商JSAPI文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_3.shtml
|
||||
// 服务商小程序文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_4.shtml
|
||||
// 电商JSAPI文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_3_3.shtml
|
||||
// 电商小程序文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_3_4.shtml
|
||||
func (c *ClientV3) V3CombineTransactionJsapi(ctx context.Context, bm gopay.BodyMap) (wxRsp *PrepayRsp, err error) {
|
||||
if bm.GetString("combine_mchid") == util.NULL {
|
||||
bm.Set("combine_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3CombinePayJsapi, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3CombinePayJsapi, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PrepayRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Prepay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 合单Native下单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_5.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_5.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_3_5.shtml
|
||||
func (c *ClientV3) V3CombineTransactionNative(ctx context.Context, bm gopay.BodyMap) (wxRsp *NativeRsp, err error) {
|
||||
if bm.GetString("combine_mchid") == util.NULL {
|
||||
bm.Set("combine_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3CombineNative, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3CombineNative, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &NativeRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Native)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 合单H5下单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_2.shtml
|
||||
func (c *ClientV3) V3CombineTransactionH5(ctx context.Context, bm gopay.BodyMap) (wxRsp *H5Rsp, err error) {
|
||||
if bm.GetString("combine_mchid") == util.NULL {
|
||||
bm.Set("combine_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3CombinePayH5, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3CombinePayH5, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &H5Rsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(H5Url)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 合单查询订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_11.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_11.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_3_11.shtml
|
||||
func (c *ClientV3) V3CombineQueryOrder(ctx context.Context, traderNo string) (wxRsp *CombineQueryOrderRsp, err error) {
|
||||
uri := fmt.Sprintf(v3CombineQuery, traderNo)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &CombineQueryOrderRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(CombineQueryOrder)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 合单关闭订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_12.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_12.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_3_12.shtml
|
||||
func (c *ClientV3) V3CombineCloseOrder(ctx context.Context, tradeNo string, bm gopay.BodyMap) (wxRsp *CloseOrderRsp, err error) {
|
||||
url := fmt.Sprintf(v3CombineClose, tradeNo)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &CloseOrderRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// (服务商、电商模式)APP下单API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_2_1.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_2_1.shtml
|
||||
func (c *ClientV3) V3PartnerTransactionApp(ctx context.Context, bm gopay.BodyMap) (wxRsp *PrepayRsp, err error) {
|
||||
if bm.GetString("sp_mchid") == util.NULL {
|
||||
bm.Set("sp_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3ApiPartnerPayApp, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ApiPartnerPayApp, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PrepayRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Prepay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// (服务商、电商模式)JSAPI/小程序下单API
|
||||
// Code = 0 is success
|
||||
// 服务商JSAPI文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_1.shtml
|
||||
// 服务商小程序文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_1.shtml
|
||||
// 电商JSAPI文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_2_2.shtml
|
||||
// 电商小程序文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_2_3.shtml
|
||||
func (c *ClientV3) V3PartnerTransactionJsapi(ctx context.Context, bm gopay.BodyMap) (wxRsp *PrepayRsp, err error) {
|
||||
if bm.GetString("sp_mchid") == util.NULL {
|
||||
bm.Set("sp_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3ApiPartnerJsapi, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ApiPartnerJsapi, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &PrepayRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Prepay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// (服务商、电商模式)Native下单API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_4_1.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_2_12.shtml
|
||||
func (c *ClientV3) V3PartnerTransactionNative(ctx context.Context, bm gopay.BodyMap) (wxRsp *NativeRsp, err error) {
|
||||
if bm.GetString("sp_mchid") == util.NULL {
|
||||
bm.Set("sp_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3ApiPartnerNative, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ApiPartnerNative, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &NativeRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Native)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// (服务商模式)H5下单API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_3_1.shtml
|
||||
func (c *ClientV3) V3PartnerTransactionH5(ctx context.Context, bm gopay.BodyMap) (wxRsp *H5Rsp, err error) {
|
||||
if bm.GetString("sp_mchid") == util.NULL {
|
||||
bm.Set("sp_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3ApiPartnerH5, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ApiPartnerH5, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &H5Rsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(H5Url)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// (服务商、电商模式)查询订单API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_2.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_2_5.shtml
|
||||
func (c *ClientV3) V3PartnerQueryOrder(ctx context.Context, orderNoType OrderNoType, orderNo string, bm gopay.BodyMap) (wxRsp *PartnerQueryOrderRsp, err error) {
|
||||
var uri string
|
||||
if bm.GetString("sp_mchid") == gopay.NULL {
|
||||
bm.Set("sp_mchid", c.Mchid)
|
||||
}
|
||||
switch orderNoType {
|
||||
case TransactionId:
|
||||
uri = fmt.Sprintf(v3ApiPartnerQueryOrderTransactionId, orderNo) + "?" + bm.EncodeURLParams()
|
||||
case OutTradeNo:
|
||||
uri = fmt.Sprintf(v3ApiPartnerQueryOrderOutTradeNo, orderNo) + "?" + bm.EncodeURLParams()
|
||||
default:
|
||||
return nil, errors.New("unsupported order number type")
|
||||
}
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &PartnerQueryOrderRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnerQueryOrder)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// (服务商、电商模式)关单API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_3.shtml
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_2_6.shtml
|
||||
func (c *ClientV3) V3PartnerCloseOrder(ctx context.Context, tradeNo string, bm gopay.BodyMap) (wxRsp *CloseOrderRsp, err error) {
|
||||
url := fmt.Sprintf(v3ApiPartnerCloseOrder, tradeNo)
|
||||
if bm.GetString("sp_mchid") == gopay.NULL {
|
||||
bm.Set("sp_mchid", c.Mchid)
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &CloseOrderRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 请求分账API
|
||||
// 微信会在接到请求后立刻返回请求接收结果,分账结果需要自行调用查询接口来获取
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_1.shtml
|
||||
func (c *ClientV3) V3ProfitShareOrder(ctx context.Context, bm gopay.BodyMap) (*ProfitShareOrderRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3ProfitShareOrder, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ProfitShareOrder, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareOrderRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareOrder)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询分账结果API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_2.shtml
|
||||
func (c *ClientV3) V3ProfitShareOrderQuery(ctx context.Context, orderNo string, bm gopay.BodyMap) (*ProfitShareOrderQueryRsp, error) {
|
||||
uri := fmt.Sprintf(v3ProfitShareQuery, orderNo) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareOrderQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareOrderQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 请求分账回退API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_3.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_3.shtml
|
||||
func (c *ClientV3) V3ProfitShareReturn(ctx context.Context, bm gopay.BodyMap) (*ProfitShareReturnRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3ProfitShareReturn, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ProfitShareReturn, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareReturnRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareReturn)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询分账回退结果API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_4.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_4.shtml
|
||||
func (c *ClientV3) V3ProfitShareReturnResult(ctx context.Context, returnNo string, bm gopay.BodyMap) (*ProfitShareReturnResultRsp, error) {
|
||||
uri := fmt.Sprintf(v3ProfitShareReturnResult, returnNo) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareReturnResultRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareReturnResult)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 解冻剩余资金API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_5.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_5.shtml
|
||||
func (c *ClientV3) V3ProfitShareOrderUnfreeze(ctx context.Context, bm gopay.BodyMap) (*ProfitShareOrderUnfreezeRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3ProfitShareUnfreeze, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ProfitShareUnfreeze, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareOrderUnfreezeRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareOrderUnfreeze)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询剩余待分金额API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_6.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_6.shtml
|
||||
func (c *ClientV3) V3ProfitShareUnsplitAmount(ctx context.Context, transId string) (*ProfitShareUnsplitAmountRsp, error) {
|
||||
url := fmt.Sprintf(v3ProfitShareUnsplitAmount, transId)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareUnsplitAmountRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareUnsplitAmount)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询最大分账比例API
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_7.shtml
|
||||
func (c *ClientV3) V3ProfitShareMerchantConfigs(ctx context.Context, subMchId string) (*ProfitShareMerchantConfigsRsp, error) {
|
||||
uri := fmt.Sprintf(v3ProfitShareMerchantConfigs, subMchId)
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareMerchantConfigsRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareMerchantConfigs)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 新增分账接收方API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_8.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_8.shtml
|
||||
func (c *ClientV3) V3ProfitShareAddReceiver(ctx context.Context, bm gopay.BodyMap) (*ProfitShareAddReceiverRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3ProfitShareAddReceiver, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ProfitShareAddReceiver, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareAddReceiverRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareAddReceiver)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 删除分账接收方API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_9.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_9.shtml
|
||||
func (c *ClientV3) V3ProfitShareDeleteReceiver(ctx context.Context, bm gopay.BodyMap) (*ProfitShareDeleteReceiverRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3ProfitShareDeleteReceiver, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ProfitShareDeleteReceiver, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareDeleteReceiverRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareDeleteReceiver)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 申请分账账单
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_1_11.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_11.shtml
|
||||
func (c *ClientV3) V3ProfitShareBills(ctx context.Context, bm gopay.BodyMap) (*ProfitShareBillsRsp, error) {
|
||||
uri := v3ProfitShareBills + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &ProfitShareBillsRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ProfitShareBills)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 申请退款API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_9.shtml
|
||||
func (c *ClientV3) V3Refund(ctx context.Context, bm gopay.BodyMap) (wxRsp *RefundRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3DomesticRefund, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3DomesticRefund, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &RefundRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(RefundOrderResponse)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询单笔退款API
|
||||
// 注意:商户查询时,bm 可传 nil;服务商时,传相应query参数
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_10.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_10.shtml
|
||||
func (c *ClientV3) V3RefundQuery(ctx context.Context, outRefundNo string, bm gopay.BodyMap) (wxRsp *RefundQueryRsp, err error) {
|
||||
uri := fmt.Sprintf(v3DomesticRefundQuery, outRefundNo)
|
||||
if bm != nil {
|
||||
uri = fmt.Sprintf(v3DomesticRefundQuery, outRefundNo) + "?" + bm.EncodeURLParams()
|
||||
}
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &RefundQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(RefundQueryResponse)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 申请退款API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_1.shtml
|
||||
func (c *ClientV3) V3EcommerceRefund(ctx context.Context, bm gopay.BodyMap) (wxRsp *EcommerceRefundRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3CommerceRefund, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3CommerceRefund, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &EcommerceRefundRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceRefund)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 通过微信支付退款单号查询退款API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_2.shtml
|
||||
func (c *ClientV3) V3EcommerceRefundQueryById(ctx context.Context, refundId string, bm gopay.BodyMap) (wxRsp *EcommerceRefundQueryRsp, err error) {
|
||||
uri := fmt.Sprintf(v3CommerceRefundQueryById, refundId) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &EcommerceRefundQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceRefundQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 通过商户退款单号查询退款API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_2.shtml
|
||||
func (c *ClientV3) V3EcommerceRefundQueryByNo(ctx context.Context, outRefundNo string, bm gopay.BodyMap) (wxRsp *EcommerceRefundQueryRsp, err error) {
|
||||
uri := fmt.Sprintf(v3CommerceRefundQueryByNo, outRefundNo) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &EcommerceRefundQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceRefundQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 垫付退款回补API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_4.shtml
|
||||
func (c *ClientV3) V3EcommerceRefundAdvance(ctx context.Context, refundId string, bm gopay.BodyMap) (wxRsp *EcommerceRefundAdvanceRsp, err error) {
|
||||
url := fmt.Sprintf(v3CommerceRefundAdvance, refundId)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &EcommerceRefundAdvanceRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceRefundAdvance)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询垫付回补结果API
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_5.shtml
|
||||
func (c *ClientV3) V3EcommerceRefundAdvanceResult(ctx context.Context, refundId string, bm gopay.BodyMap) (wxRsp *EcommerceRefundAdvanceRsp, err error) {
|
||||
uri := fmt.Sprintf(v3CommerceRefundAdvanceResult, refundId) + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &EcommerceRefundAdvanceRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceRefundAdvance)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+361
@@ -0,0 +1,361 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 创单结单合并API
|
||||
// Code = 0 is success
|
||||
// 注意:限制条件:【免确认订单模式】,用户已授权状态下,可调用该接口。
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_1.shtml
|
||||
func (c *ClientV3) V3ScoreDirectComplete(ctx context.Context, bm gopay.BodyMap) (wxRsp *ScoreDirectCompleteRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3ScoreDirectComplete, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ScoreDirectComplete, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScoreDirectCompleteRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScoreDirectComplete)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商户预授权API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_2.shtml
|
||||
func (c *ClientV3) V3ScorePermission(ctx context.Context, bm gopay.BodyMap) (wxRsp *ScorePermissionRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3ScorePermission, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ScorePermission, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScorePermissionRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScorePermission)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询用户授权记录(授权协议号)API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_3.shtml
|
||||
func (c *ClientV3) V3ScorePermissionQuery(ctx context.Context, authCode, serviceId string) (wxRsp *ScorePermissionQueryRsp, err error) {
|
||||
uri := fmt.Sprintf(v3ScorePermissionQuery, authCode) + "?service_id=" + serviceId
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScorePermissionQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScorePermissionQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 解除用户授权关系(授权协议号)API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_4.shtml
|
||||
func (c *ClientV3) V3ScorePermissionTerminate(ctx context.Context, authCode, serviceId, reason string) (wxRsp *EmptyRsp, err error) {
|
||||
url := fmt.Sprintf(v3ScorePermissionTerminate, authCode)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("service_id", serviceId).
|
||||
Set("reason", reason)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询用户授权记录(openid)API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_5.shtml
|
||||
func (c *ClientV3) V3ScorePermissionOpenidQuery(ctx context.Context, appid, openid, serviceid string) (wxRsp *ScorePermissionOpenidQueryRsp, err error) {
|
||||
uri := fmt.Sprintf(v3ScorePermissionOpenidQuery, openid) + "?appid=" + appid + "&service_id=" + serviceid
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScorePermissionOpenidQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScorePermissionOpenidQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 解除用户授权关系(openid)API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_6.shtml
|
||||
func (c *ClientV3) V3ScorePermissionOpenidTerminate(ctx context.Context, appid, openid, serviceid, reason string) (wxRsp *EmptyRsp, err error) {
|
||||
url := fmt.Sprintf(v3ScorePermissionOpenidTerminate, openid)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("service_id", serviceid).
|
||||
Set("appid", appid).
|
||||
Set("reason", reason)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 创建支付分订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_14.shtml
|
||||
func (c *ClientV3) V3ScoreOrderCreate(ctx context.Context, bm gopay.BodyMap) (wxRsp *ScoreOrderCreateRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3ScoreOrderCreate, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3ScoreOrderCreate, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScoreOrderCreateRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScoreOrderCreate)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询支付分订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_15.shtml
|
||||
func (c *ClientV3) V3ScoreOrderQuery(ctx context.Context, orderNoType OrderNoType, appid, orderNo, serviceid string) (wxRsp *ScoreOrderQueryRsp, err error) {
|
||||
var uri string
|
||||
switch orderNoType {
|
||||
case OutTradeNo:
|
||||
uri = v3ScoreOrderQuery + "?appid=" + appid + "&out_order_no=" + orderNo + "&service_id=" + serviceid
|
||||
case QueryId:
|
||||
uri = v3ScoreOrderQuery + "?appid=" + appid + "&query_id=" + orderNo + "&service_id=" + serviceid
|
||||
default:
|
||||
return nil, errors.New("unsupported order number type")
|
||||
}
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScoreOrderQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScoreOrderQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 取消支付分订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_16.shtml
|
||||
func (c *ClientV3) V3ScoreOrderCancel(ctx context.Context, appid, tradeNo, serviceid, reason string) (wxRsp *ScoreOrderCancelRsp, err error) {
|
||||
url := fmt.Sprintf(v3ScoreOrderCancel, tradeNo)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("appid", appid).
|
||||
Set("service_id", serviceid).
|
||||
Set("reason", reason)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScoreOrderCancelRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScoreOrderCancel)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 修改订单金额API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_17.shtml
|
||||
func (c *ClientV3) V3ScoreOrderModify(ctx context.Context, tradeNo string, bm gopay.BodyMap) (wxRsp *ScoreOrderModifyRsp, err error) {
|
||||
url := fmt.Sprintf(v3ScoreOrderModify, tradeNo)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScoreOrderModifyRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScoreOrderModify)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 完结支付分订单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_18.shtml
|
||||
func (c *ClientV3) V3ScoreOrderComplete(ctx context.Context, tradeNo string, bm gopay.BodyMap) (wxRsp *ScoreOrderCompleteRsp, err error) {
|
||||
url := fmt.Sprintf(v3ScoreOrderComplete, tradeNo)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScoreOrderCompleteRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScoreOrderComplete)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商户发起催收扣款API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_19.shtml
|
||||
func (c *ClientV3) V3ScoreOrderPay(ctx context.Context, appid, tradeNo, serviceid string) (wxRsp *ScoreOrderPayRsp, err error) {
|
||||
url := fmt.Sprintf(v3ScoreOrderPay, tradeNo)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("appid", appid).
|
||||
Set("service_id", serviceid)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScoreOrderPayRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScoreOrderPay)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 同步服务订单信息API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_20.shtml
|
||||
func (c *ClientV3) V3ScoreOrderSync(ctx context.Context, tradeNo string, bm gopay.BodyMap) (wxRsp *ScoreOrderSyncRsp, err error) {
|
||||
url := fmt.Sprintf(v3ScoreOrderSync, tradeNo)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &ScoreOrderSyncRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(ScoreOrderSync)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
"github.com/go-pay/gopay/pkg/xlog"
|
||||
"github.com/go-pay/gopay/pkg/xpem"
|
||||
)
|
||||
|
||||
// Deprecated
|
||||
// 推荐使用 wechat.V3VerifySignByPK()
|
||||
func V3VerifySign(timestamp, nonce, signBody, sign, wxPubKeyContent string) (err error) {
|
||||
publicKey, err := xpem.DecodePublicKey([]byte(wxPubKeyContent))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
str := timestamp + "\n" + nonce + "\n" + signBody + "\n"
|
||||
signBytes, _ := base64.StdEncoding.DecodeString(sign)
|
||||
|
||||
h := sha256.New()
|
||||
h.Write([]byte(str))
|
||||
if err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, h.Sum(nil), signBytes); err != nil {
|
||||
return fmt.Errorf("[%w]: %v", gopay.VerifySignatureErr, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 微信V3 版本验签(同步/异步)
|
||||
// wxPublicKey:微信平台证书公钥内容,通过 client.WxPublicKey() 获取
|
||||
func V3VerifySignByPK(timestamp, nonce, signBody, sign string, wxPublicKey *rsa.PublicKey) (err error) {
|
||||
str := timestamp + "\n" + nonce + "\n" + signBody + "\n"
|
||||
signBytes, _ := base64.StdEncoding.DecodeString(sign)
|
||||
|
||||
h := sha256.New()
|
||||
h.Write([]byte(str))
|
||||
if err = rsa.VerifyPKCS1v15(wxPublicKey, crypto.SHA256, h.Sum(nil), signBytes); err != nil {
|
||||
return fmt.Errorf("[%w]: %v", gopay.VerifySignatureErr, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PaySignOfJSAPI 获取 JSAPI paySign
|
||||
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
|
||||
func (c *ClientV3) PaySignOfJSAPI(appid, prepayid string) (jsapi *JSAPIPayParams, err error) {
|
||||
ts := util.Int642String(time.Now().Unix())
|
||||
nonceStr := util.RandomString(32)
|
||||
pkg := "prepay_id=" + prepayid
|
||||
|
||||
_str := appid + "\n" + ts + "\n" + nonceStr + "\n" + pkg + "\n"
|
||||
sign, err := c.rsaSign(_str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
jsapi = &JSAPIPayParams{
|
||||
AppId: appid,
|
||||
TimeStamp: ts,
|
||||
NonceStr: nonceStr,
|
||||
Package: pkg,
|
||||
SignType: SignTypeRSA,
|
||||
PaySign: sign,
|
||||
}
|
||||
return jsapi, nil
|
||||
}
|
||||
|
||||
// PaySignOfApp 获取 App sign
|
||||
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_4.shtml
|
||||
func (c *ClientV3) PaySignOfApp(appid, prepayid string) (app *AppPayParams, err error) {
|
||||
ts := util.Int642String(time.Now().Unix())
|
||||
nonceStr := util.RandomString(32)
|
||||
|
||||
_str := appid + "\n" + ts + "\n" + nonceStr + "\n" + prepayid + "\n"
|
||||
sign, err := c.rsaSign(_str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app = &AppPayParams{
|
||||
Appid: appid,
|
||||
Partnerid: c.Mchid,
|
||||
Prepayid: prepayid,
|
||||
Package: "Sign=WXPay",
|
||||
Noncestr: nonceStr,
|
||||
Timestamp: ts,
|
||||
Sign: sign,
|
||||
}
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// PaySignOfApplet 获取 小程序 paySign
|
||||
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_4.shtml
|
||||
func (c *ClientV3) PaySignOfApplet(appid, prepayid string) (applet *AppletParams, err error) {
|
||||
jsapi, err := c.PaySignOfJSAPI(appid, prepayid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
applet = &AppletParams{
|
||||
AppId: jsapi.AppId,
|
||||
TimeStamp: jsapi.TimeStamp,
|
||||
NonceStr: jsapi.NonceStr,
|
||||
Package: jsapi.Package,
|
||||
SignType: jsapi.SignType,
|
||||
PaySign: jsapi.PaySign,
|
||||
}
|
||||
return applet, nil
|
||||
}
|
||||
|
||||
// v3 鉴权请求Header
|
||||
func (c *ClientV3) authorization(method, path string, bm gopay.BodyMap) (string, error) {
|
||||
var (
|
||||
jb = ""
|
||||
timestamp = time.Now().Unix()
|
||||
nonceStr = util.RandomString(32)
|
||||
)
|
||||
if bm != nil {
|
||||
jb = bm.JsonBody()
|
||||
}
|
||||
ts := util.Int642String(timestamp)
|
||||
_str := method + "\n" + path + "\n" + ts + "\n" + nonceStr + "\n" + jb + "\n"
|
||||
if c.DebugSwitch == gopay.DebugOn {
|
||||
xlog.Debugf("Wechat_V3_SignString:\n%s", _str)
|
||||
}
|
||||
sign, err := c.rsaSign(_str)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Authorization + ` mchid="` + c.Mchid + `",nonce_str="` + nonceStr + `",timestamp="` + ts + `",serial_no="` + c.SerialNo + `",signature="` + sign + `"`, nil
|
||||
}
|
||||
|
||||
func (c *ClientV3) rsaSign(str string) (string, error) {
|
||||
if c.privateKey == nil {
|
||||
return "", errors.New("privateKey can't be nil")
|
||||
}
|
||||
h := sha256.New()
|
||||
h.Write([]byte(str))
|
||||
result, err := rsa.SignPKCS1v15(rand.Reader, c.privateKey, crypto.SHA256, h.Sum(nil))
|
||||
if err != nil {
|
||||
return util.NULL, fmt.Errorf("[%w]: %+v", gopay.SignatureErr, err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(result), nil
|
||||
}
|
||||
|
||||
// 自动同步请求验签
|
||||
func (c *ClientV3) verifySyncSign(si *SignInfo) (err error) {
|
||||
if c.autoSign && c.wxPublicKey != nil {
|
||||
if si != nil {
|
||||
str := si.HeaderTimestamp + "\n" + si.HeaderNonce + "\n" + si.SignBody + "\n"
|
||||
signBytes, _ := base64.StdEncoding.DecodeString(si.HeaderSignature)
|
||||
|
||||
h := sha256.New()
|
||||
h.Write([]byte(str))
|
||||
if err = rsa.VerifyPKCS1v15(c.wxPublicKey, crypto.SHA256, h.Sum(nil), signBytes); err != nil {
|
||||
return fmt.Errorf("[%w]: %v", gopay.VerifySignatureErr, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.New("auto verify sign, bug SignInfo is nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 服务人员注册API
|
||||
// 注意:入参加密字段数据加密:client.V3EncryptText()
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_4_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_4_1.shtml
|
||||
func (c *ClientV3) V3SmartGuideReg(ctx context.Context, bm gopay.BodyMap) (wxRsp *SmartGuideRegRsp, err error) {
|
||||
authorization, err := c.authorization(MethodPost, v3GuideReg, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3GuideReg, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &SmartGuideRegRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(SmartGuideReg)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 服务人员分配API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_4_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_4_2.shtml
|
||||
func (c *ClientV3) V3SmartGuideAssign(ctx context.Context, guideId, tradeNo string) (wxRsp *EmptyRsp, err error) {
|
||||
url := fmt.Sprintf(v3GuideAssign, guideId)
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("out_trade_no", tradeNo)
|
||||
authorization, err := c.authorization(MethodPost, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 服务人员查询API
|
||||
// 注意:入参加密字段数据加密:client.V3EncryptText(),返回参数加密字段解密:client.V3DecryptText()
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_4_3.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_4_3.shtml
|
||||
func (c *ClientV3) V3SmartGuideQuery(ctx context.Context, bm gopay.BodyMap) (wxRsp *SmartGuideQueryRsp, err error) {
|
||||
if err = bm.CheckEmptyError("store_id"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uri := v3GuideQuery + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &SmartGuideQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(SmartGuideQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 服务人员信息更新API
|
||||
// 注意:入参加密字段数据加密:client.V3EncryptText()
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter8_4_4.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_4_4.shtml
|
||||
func (c *ClientV3) V3SmartGuideUpdate(ctx context.Context, guideId string, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) {
|
||||
url := fmt.Sprintf(v3GuideUpdate, guideId)
|
||||
authorization, err := c.authorization(MethodPATCH, url, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPatch(ctx, bm, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp = &EmptyRsp{Code: Success, SignInfo: si}
|
||||
if res.StatusCode != http.StatusNoContent {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+413
@@ -0,0 +1,413 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
)
|
||||
|
||||
// 发起批量转账API
|
||||
// 注意:入参加密字段数据加密:client.V3EncryptText()
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_1.shtml
|
||||
func (c *ClientV3) V3Transfer(ctx context.Context, bm gopay.BodyMap) (*TransferRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3Transfer, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3Transfer, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Transfer)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 发起批量转账API(服务商)
|
||||
// 注意:入参加密字段数据加密:client.V3EncryptText()
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_1.shtml
|
||||
func (c *ClientV3) V3PartnerTransfer(ctx context.Context, bm gopay.BodyMap) (*TransferRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3PartnerTransfer, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3PartnerTransfer, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Transfer)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 微信批次单号查询批次单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_2.shtml
|
||||
func (c *ClientV3) V3TransferQuery(ctx context.Context, batchId string, bm gopay.BodyMap) (*TransferQueryRsp, error) {
|
||||
url := fmt.Sprintf(v3TransferQuery, batchId)
|
||||
bm.Remove("batch_id")
|
||||
uri := url + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TransferQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 微信批次单号查询批次单API(服务商)
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_2.shtml
|
||||
func (c *ClientV3) V3PartnerTransferQuery(ctx context.Context, batchId string, bm gopay.BodyMap) (*PartnerTransferQueryRsp, error) {
|
||||
url := fmt.Sprintf(v3PartnerTransferQuery, batchId)
|
||||
bm.Remove("batch_id")
|
||||
uri := url + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &PartnerTransferQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnerTransferQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 微信明细单号查询明细单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_3.shtml
|
||||
func (c *ClientV3) V3TransferDetail(ctx context.Context, batchId, detailId string) (*TransferDetailRsp, error) {
|
||||
url := fmt.Sprintf(v3TransferDetail, batchId, detailId)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TransferDetailQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 微信明细单号查询明细单API(服务商)
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_3.shtml
|
||||
func (c *ClientV3) V3PartnerTransferDetail(ctx context.Context, batchId, detailId string) (*PartnerTransferDetailRsp, error) {
|
||||
url := fmt.Sprintf(v3PartnerTransferDetail, batchId, detailId)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &PartnerTransferDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnerTransferDetail)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
// 推荐直接使用 client.V3TransferDetail() 方法
|
||||
func (c *ClientV3) V3TransferDetailQuery(ctx context.Context, batchId, detailId string) (*TransferDetailRsp, error) {
|
||||
return c.V3TransferDetail(ctx, batchId, detailId)
|
||||
}
|
||||
|
||||
// 商家批次单号查询批次单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_4.shtml
|
||||
func (c *ClientV3) V3TransferMerchantQuery(ctx context.Context, outBatchNo string, bm gopay.BodyMap) (*TransferMerchantQueryRsp, error) {
|
||||
url := fmt.Sprintf(v3TransferMerchantQuery, outBatchNo)
|
||||
bm.Remove("out_batch_no")
|
||||
uri := url + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferMerchantQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TransferMerchantQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商家批次单号查询批次单API(服务商)
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_4.shtml
|
||||
func (c *ClientV3) V3PartnerTransferMerchantQuery(ctx context.Context, outBatchNo string, bm gopay.BodyMap) (*PartnerTransferMerchantQueryRsp, error) {
|
||||
url := fmt.Sprintf(v3PartnerTransferMerchantQuery, outBatchNo)
|
||||
bm.Remove("out_batch_no")
|
||||
uri := url + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &PartnerTransferMerchantQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnerTransferMerchantQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商家明细单号查询明细单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_5.shtml
|
||||
func (c *ClientV3) V3TransferMerchantDetail(ctx context.Context, outBatchNo, outDetailNo string) (*TransferMerchantDetailRsp, error) {
|
||||
url := fmt.Sprintf(v3TransferMerchantDetail, outBatchNo, outDetailNo)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferMerchantDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TransferMerchantDetail)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 商家明细单号查询明细单API(服务商)
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_5.shtml
|
||||
func (c *ClientV3) V3PartnerTransferMerchantDetail(ctx context.Context, outBatchNo, outDetailNo string) (*PartnerTransferMerchantDetailRsp, error) {
|
||||
url := fmt.Sprintf(v3PartnerTransferMerchantDetail, outBatchNo, outDetailNo)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &PartnerTransferMerchantDetailRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(PartnerTransferMerchantDetail)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
// 推荐直接使用 client.V3TransferMerchantDetail() 方法
|
||||
func (c *ClientV3) V3TransferMerchantDetailQuery(ctx context.Context, outBatchNo, outDetailNo string) (*TransferMerchantDetailRsp, error) {
|
||||
return c.V3TransferMerchantDetail(ctx, outBatchNo, outDetailNo)
|
||||
}
|
||||
|
||||
// 转账电子回单申请受理API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_1.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_1.shtml
|
||||
func (c *ClientV3) V3TransferReceipt(ctx context.Context, outBatchNo string) (*TransferReceiptRsp, error) {
|
||||
bm := make(gopay.BodyMap)
|
||||
bm.Set("out_batch_no", outBatchNo)
|
||||
|
||||
authorization, err := c.authorization(MethodPost, v3TransferReceipt, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3TransferReceipt, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferReceiptRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TransferReceipt)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询转账电子回单API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_2.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_2.shtml
|
||||
func (c *ClientV3) V3TransferReceiptQuery(ctx context.Context, outBatchNo string) (*TransferReceiptQueryRsp, error) {
|
||||
url := fmt.Sprintf(v3TransferReceiptQuery, outBatchNo)
|
||||
authorization, err := c.authorization(MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, url, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferReceiptQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TransferReceiptQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 转账明细电子回单受理API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_4.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_4.shtml
|
||||
func (c *ClientV3) V3TransferDetailReceipt(ctx context.Context, bm gopay.BodyMap) (*TransferDetailReceiptRsp, error) {
|
||||
authorization, err := c.authorization(MethodPost, v3TransferDetailReceipt, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3TransferDetailReceipt, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferDetailReceiptRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TransferDetailReceipt)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询转账明细电子回单受理结果API
|
||||
// Code = 0 is success
|
||||
// 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_5.shtml
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_5.shtml
|
||||
func (c *ClientV3) V3TransferDetailReceiptQuery(ctx context.Context, bm gopay.BodyMap) (*TransferDetailReceiptQueryRsp, error) {
|
||||
uri := v3TransferDetailReceiptQuery + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &TransferDetailReceiptQueryRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TransferDetailReceiptQuery)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
package wechat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/pkg/util"
|
||||
)
|
||||
|
||||
// 特约商户余额提现、二级商户预约提现
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter6_1.shtml
|
||||
func (c *ClientV3) V3Withdraw(ctx context.Context, bm gopay.BodyMap) (*WithdrawRsp, error) {
|
||||
if err := bm.CheckEmptyError("sub_mchid", "out_request_no", "amount"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3Withdraw, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3Withdraw, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &WithdrawRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(Withdraw)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 查询特约商户提现状态、二级商户查询预约提现状态
|
||||
// 注意:withdrawId 和 outRequestNo 二选一
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter6_2.shtml
|
||||
func (c *ClientV3) V3WithdrawStatus(ctx context.Context, withdrawId, outRequestNo string, bm gopay.BodyMap) (*WithdrawStatusRsp, error) {
|
||||
if withdrawId == gopay.NULL && outRequestNo == gopay.NULL {
|
||||
return nil, fmt.Errorf("[%w]: withdrawId[%s] and outRequestNo[%s] empty at the same time", gopay.MissParamErr, withdrawId, outRequestNo)
|
||||
}
|
||||
var uri string
|
||||
if withdrawId != gopay.NULL {
|
||||
uri = fmt.Sprintf(v3WithdrawStatusById, withdrawId) + "?" + bm.EncodeURLParams()
|
||||
} else {
|
||||
uri = fmt.Sprintf(v3WithdrawStatusByNo, outRequestNo) + "?" + bm.EncodeURLParams()
|
||||
}
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &WithdrawStatusRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(WithdrawStatus)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 电商平台预约提现
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_8_2.shtml
|
||||
func (c *ClientV3) V3EcommerceWithdraw(ctx context.Context, bm gopay.BodyMap) (*EcommerceWithdrawRsp, error) {
|
||||
if err := bm.CheckEmptyError("out_request_no", "amount", "account_type"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorization, err := c.authorization(MethodPost, v3EcommerceWithdraw, bm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceWithdraw, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp := &EcommerceWithdrawRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceWithdraw)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 电商平台查询预约提现状态
|
||||
// 注意:withdrawId 和 outRequestNo 二选一
|
||||
// Code = 0 is success
|
||||
// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_8_6.shtml
|
||||
func (c *ClientV3) V3EcommerceWithdrawStatus(ctx context.Context, withdrawId, outRequestNo string) (*EcommerceWithdrawStatusRsp, error) {
|
||||
if withdrawId == gopay.NULL && outRequestNo == gopay.NULL {
|
||||
return nil, fmt.Errorf("[%w]: withdrawId[%s] and outRequestNo[%s] empty at the same time", gopay.MissParamErr, withdrawId, outRequestNo)
|
||||
}
|
||||
var uri string
|
||||
if withdrawId != gopay.NULL {
|
||||
uri = fmt.Sprintf(v3EcommerceWithdrawStatusById, withdrawId)
|
||||
} else {
|
||||
uri = fmt.Sprintf(v3EcommerceWithdrawStatusByNo, outRequestNo)
|
||||
}
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wxRsp := &EcommerceWithdrawStatusRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(EcommerceWithdrawStatus)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
|
||||
// 按日下载提现异常文件
|
||||
// 注意:如 bill_date 为空,默认查前一天的
|
||||
// Code = 0 is success
|
||||
// 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter6_3.shtml
|
||||
func (c *ClientV3) V3WithdrawDownloadErrBill(ctx context.Context, bm gopay.BodyMap) (wxRsp *BillRsp, err error) {
|
||||
if bm != nil {
|
||||
if bm.GetString("bill_date") == util.NULL {
|
||||
now := time.Now()
|
||||
yesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, time.Local).Format(util.DateLayout)
|
||||
bm.Set("bill_date", yesterday)
|
||||
}
|
||||
bm.Remove("bill_type")
|
||||
}
|
||||
uri := fmt.Sprintf(v3WithdrawDownloadErrBill, "NO_SUCC") + "?" + bm.EncodeURLParams()
|
||||
authorization, err := c.authorization(MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, si, bs, err := c.doProdGet(ctx, uri, authorization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wxRsp = &BillRsp{Code: Success, SignInfo: si}
|
||||
wxRsp.Response = new(TradeBill)
|
||||
if err = json.Unmarshal(bs, wxRsp.Response); err != nil {
|
||||
return nil, fmt.Errorf("[%w]: %v, bytes: %s", gopay.UnmarshalErr, err, string(bs))
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
wxRsp.Code = res.StatusCode
|
||||
wxRsp.Error = string(bs)
|
||||
return wxRsp, nil
|
||||
}
|
||||
return wxRsp, c.verifySyncSign(si)
|
||||
}
|
||||
Reference in New Issue
Block a user