From 75bd08280be8c0b7cb8cbe9b82dfbc6c9105004a Mon Sep 17 00:00:00 2001 From: Jerry <85411418@qq.com> Date: Wed, 9 Feb 2022 23:54:49 +0800 Subject: [PATCH] v1.5.71 (#226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 新增微信 银行组件(服务商)相关接口 * v1.5.71 --- alipay/client.go | 2 +- alipay/member_api.go | 4 +- alipay/member_api_test.go | 2 +- constant.go | 2 +- doc/wechat_v3.md | 7 ++ go.mod | 2 +- go.sum | 4 +- release_note.txt | 4 +- wechat/v3/bank.go | 175 ++++++++++++++++++++++++++++++++++++++ wechat/v3/client_test.go | 16 ++++ wechat/v3/constant.go | 8 ++ wechat/v3/model.go | 106 +++++++++++++++++++++++ 12 files changed, 323 insertions(+), 9 deletions(-) create mode 100644 wechat/v3/bank.go diff --git a/alipay/client.go b/alipay/client.go index 84ef644f..e49d665f 100644 --- a/alipay/client.go +++ b/alipay/client.go @@ -235,7 +235,7 @@ func (a *Client) doAliPay(ctx context.Context, bm gopay.BodyMap, method string, if aat != util.NULL { pubBody.Set("app_auth_token", aat) } - if method == "alipay.user.info.share" { + if len(authToken) > 0 { pubBody.Set("auth_token", authToken[0]) } if bodyStr != util.NULL { diff --git a/alipay/member_api.go b/alipay/member_api.go index 942e5f27..7c01579f 100644 --- a/alipay/member_api.go +++ b/alipay/member_api.go @@ -394,9 +394,9 @@ func (a *Client) UserCertdocCertverifyPreconsult(ctx context.Context, bm gopay.B // alipay.user.certdoc.certverify.consult(实名证件信息比对验证咨询) // 文档地址:https://opendocs.alipay.com/apis/api_2/alipay.user.certdoc.certverify.consult -func (a *Client) UserCertdocCertverifyConsult(ctx context.Context, bm gopay.BodyMap) (aliRsp *UserCertdocCertverifyConsultRsp, err error) { +func (a *Client) UserCertdocCertverifyConsult(ctx context.Context, bm gopay.BodyMap, authToken string) (aliRsp *UserCertdocCertverifyConsultRsp, err error) { var bs []byte - if bs, err = a.doAliPay(ctx, bm, "alipay.user.certdoc.certverify.consult"); err != nil { + if bs, err = a.doAliPay(ctx, bm, "alipay.user.certdoc.certverify.consult", authToken); err != nil { return nil, err } aliRsp = new(UserCertdocCertverifyConsultRsp) diff --git a/alipay/member_api_test.go b/alipay/member_api_test.go index 41c4c34b..e355794b 100644 --- a/alipay/member_api_test.go +++ b/alipay/member_api_test.go @@ -234,7 +234,7 @@ func TestUserCertdocCertverifyConsult(t *testing.T) { bm := make(gopay.BodyMap) bm.Set("verify_id", "671ffcda5447bc87e9ed2f669eb143d4") // 发起请求 - aliRsp, err := client.UserCertdocCertverifyConsult(ctx, bm) + aliRsp, err := client.UserCertdocCertverifyConsult(ctx, bm, "auth_token") if err != nil { xlog.Error(err) return diff --git a/constant.go b/constant.go index 7620db23..0163c793 100644 --- a/constant.go +++ b/constant.go @@ -7,7 +7,7 @@ const ( OK = "OK" DebugOff = 0 DebugOn = 1 - Version = "1.5.70" + Version = "1.5.71" ) type DebugSwitch int8 diff --git a/doc/wechat_v3.md b/doc/wechat_v3.md index f0f545ba..e9d775f0 100644 --- a/doc/wechat_v3.md +++ b/doc/wechat_v3.md @@ -384,6 +384,13 @@ wechat.V3DecryptScoreNotifyCipherText() * 查询退款ByNo:`client.V3EcommerceRefundQueryByNo()` * 垫付退款回补:`client.V3EcommerceRefundAdvance()` * 查询垫付回补结果:`client.V3EcommerceRefundAdvanceResult()` +* 银行组件(服务商) + * 获取对私银行卡号开户银行:`client.V3BankSearchBank()` + * 查询支持个人业务的银行列表:`client.V3BankSearchPersonalList()` + * 查询支持对公业务的银行列表:`client.V3BankSearchCorporateList()` + * 查询省份列表:`client.V3BankSearchProvinceList()` + * 查询城市列表:`client.V3BankSearchCityList()` + * 查询支行列表:`client.V3BankSearchBranchList()` ### 微信v3公共 API diff --git a/go.mod b/go.mod index 971981b5..3f354dfa 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/go-pay/gopay go 1.16 -require golang.org/x/crypto v0.0.0-20211202192323-5770296d904e +require golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 diff --git a/go.sum b/go.sum index 759e2bbf..78b6464d 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8= -golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 h1:BkypuErRT9A9I/iljuaG3/zdMjd/J6m8tKKJQtGfSdA= +golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/release_note.txt b/release_note.txt index 0435aaf5..98ad9468 100644 --- a/release_note.txt +++ b/release_note.txt @@ -1,6 +1,8 @@ -版本号:Release 1.5.70 +版本号:Release 1.5.71 修改记录: (1) 微信V2:去除所有微信小程序、公众号相关接口,请使用 wechat-sdk + (2) 支付宝:client.UserCertdocCertverifyConsult() 方法,增加 authToken 参数 + (2) 微信V3:新增 银行组件(服务商) 相关接口,详情查看v3文档最下方的接口列表 版本号:Release 1.5.69 修改记录: diff --git a/wechat/v3/bank.go b/wechat/v3/bank.go new file mode 100644 index 00000000..de02717d --- /dev/null +++ b/wechat/v3/bank.go @@ -0,0 +1,175 @@ +package wechat + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "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=" + 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("json.Unmarshal(%s):%w", string(bs), err) + } + 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("json.Unmarshal(%s):%w", string(bs), err) + } + 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("json.Unmarshal(%s):%w", string(bs), err) + } + 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("json.Unmarshal(%s):%w", string(bs), err) + } + 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("json.Unmarshal(%s):%w", string(bs), err) + } + 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("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} diff --git a/wechat/v3/client_test.go b/wechat/v3/client_test.go index 9911e8f1..53d18343 100644 --- a/wechat/v3/client_test.go +++ b/wechat/v3/client_test.go @@ -527,4 +527,20 @@ func TestV3Withdraw(t *testing.T) { return } xlog.Debugf("wxRsp: %#v", wxRsp) + xlog.Debugf("wxRsp.Response: %#v", wxRsp.Response) +} + +func TestV3BankSearchBank(t *testing.T) { + encryptText, err := client.V3EncryptText("6213123456781234") + if err != nil { + xlog.Error(err) + return + } + wxRsp, err := client.V3BankSearchBank(ctx, encryptText) + if err != nil { + xlog.Error(err) + return + } + xlog.Debugf("wxRsp: %#v", wxRsp) + xlog.Debugf("wxRsp.Response: %#v", wxRsp.Response) } diff --git a/wechat/v3/constant.go b/wechat/v3/constant.go index 7b395d95..018e120d 100644 --- a/wechat/v3/constant.go +++ b/wechat/v3/constant.go @@ -235,6 +235,14 @@ const ( 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" // 审核中 diff --git a/wechat/v3/model.go b/wechat/v3/model.go index 780ace2d..942dce24 100644 --- a/wechat/v3/model.go +++ b/wechat/v3/model.go @@ -932,6 +932,54 @@ type EcommerceRefundAdvanceRsp struct { Error string `json:"-"` } +// 获取对私银行卡号开户银行 Rsp +type BankSearchBankRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *BankSearchBank `json:"response,omitempty"` + Error string `json:"-"` +} + +// 查询支持个人业务的银行列表 Rsp +type BankSearchPersonalListRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *BankSearchList `json:"response,omitempty"` + Error string `json:"-"` +} + +// 查询支持对公业务的银行列表 Rsp +type BankSearchCorporateListRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *BankSearchList `json:"response,omitempty"` + Error string `json:"-"` +} + +// 查询省份列表 Rsp +type BankSearchProvinceListRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *BankSearchProvince `json:"response,omitempty"` + Error string `json:"-"` +} + +// 查询城市列表 Rsp +type BankSearchCityListRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *BankSearchCity `json:"response,omitempty"` + Error string `json:"-"` +} + +// 查询支行列表 Rsp +type BankSearchBranchListRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *BankSearchBranch `json:"response,omitempty"` + Error string `json:"-"` +} + // ==================================分割================================== type JSAPIPayParams struct { @@ -2596,3 +2644,61 @@ type EcommerceRefundAdvance struct { Result string `json:"result"` // 垫付回补结果 SuccessTime string `json:"success_time"` // 垫付回补完成时间 } + +type BankSearchBank struct { + TotalCount int `json:"total_count"` // 查询数据总条数 + Data []*BankInfo `json:"data,omitempty"` // 银行列表 +} + +type BankInfo struct { + BankAlias string `json:"bank_alias"` // 银行别名 + BankAliasCode string `json:"bank_alias_code"` // 银行别名编码 + AccountBank string `json:"account_bank"` // 开户银行 + AccountBankCode int `json:"account_bank_code"` // 开户银行编码 + NeedBankBranch bool `json:"need_bank_branch"` // 是否需要填写支行 +} + +type BankSearchList struct { + TotalCount int `json:"total_count"` // 查询数据总条数 + Count int `json:"count"` // 本次查询数据条数 + Offset int `json:"offset"` // 本次查询偏移量 + Data []*BankInfo `json:"data,omitempty"` // 银行列表 + Links *Link `json:"links"` // 分页链接 +} + +type BankSearchProvince struct { + TotalCount int `json:"total_count"` // 查询数据总条数 + Data []*ProvinceInfo `json:"data,omitempty"` // 省份列表 +} + +type ProvinceInfo struct { + ProvinceName string `json:"province_name"` // 省份名称 + ProvinceCode int `json:"province_code"` // 省份编码 +} + +type BankSearchCity struct { + TotalCount int `json:"total_count"` // 查询数据总条数 + Data []*CityInfo `json:"data,omitempty"` // 城市列表 +} + +type CityInfo struct { + CityName string `json:"city_name"` // 城市名称 + CityCode int `json:"city_code"` // 城市编码 +} + +type BankSearchBranch struct { + TotalCount int `json:"total_count"` // 查询数据总条数 + Count int `json:"count"` // 本次查询数据条数 + Offset int `json:"offset"` // 本次查询偏移量 + BankAlias string `json:"bank_alias"` // 银行别名 + BankAliasCode string `json:"bank_alias_code"` // 银行别名编码 + AccountBank string `json:"account_bank"` // 开户银行 + AccountBankCode int `json:"account_bank_code"` // 开户银行编码 + Data []*BankBranchInfo `json:"data,omitempty"` // 支行列表 + Links *Link `json:"links"` // 分页链接 +} + +type BankBranchInfo struct { + BankBranchName string `json:"bank_branch_name"` // 开户银行支行名称 + BankBranchId string `json:"bank_branch_id"` // 开户银行支行联行号 +}