| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 |
- /*
- * Copyright silenceper/wechat Author(https://silenceper.com/wechat/). All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * You can obtain one at https://github.com/silenceper/wechat.
- *
- */
- package virtualpayment
- import (
- "context"
- "crypto/hmac"
- "crypto/sha256"
- "encoding/hex"
- "encoding/json"
- "errors"
- "strings"
- "github.com/silenceper/wechat/v2/util"
- )
- // SetSessionKey 设置 sessionKey
- func (s *VirtualPayment) SetSessionKey(sessionKey string) {
- s.sessionKey = sessionKey
- }
- // QueryUserBalance 查询虚拟支付余额
- func (s *VirtualPayment) QueryUserBalance(ctx context.Context, in *QueryUserBalanceRequest) (out *QueryUserBalanceResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: queryUserBalance,
- Content: string(jsonByte),
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "QueryUserBalance"); err != nil {
- return
- }
- return
- }
- // CurrencyPay currency pay 扣减代币(一般用于代币支付)
- func (s *VirtualPayment) CurrencyPay(ctx context.Context, in *CurrencyPayRequest) (out *CurrencyPayResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: currencyPay,
- Content: string(jsonByte),
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "CurrencyPay"); err != nil {
- return
- }
- return
- }
- // QueryOrder 查询创建的订单(现金单,非代币单)
- func (s *VirtualPayment) QueryOrder(ctx context.Context, in *QueryOrderRequest) (out *QueryOrderResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: queryOrder,
- Signature: EmptyString,
- Content: string(jsonByte),
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "QueryOrder"); err != nil {
- return
- }
- return
- }
- // CancelCurrencyPay 取消订单 代币支付退款 (currency_pay 接口的逆操作)
- func (s *VirtualPayment) CancelCurrencyPay(ctx context.Context, in *CancelCurrencyPayRequest) (out *CancelCurrencyPayResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: cancelCurrencyPay,
- Content: string(jsonByte),
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "CancelCurrencyPay"); err != nil {
- return
- }
- return
- }
- // NotifyProvideGoods 通知发货
- // 通知已经发货完成(只能通知现金单),正常通过 xpay_goods_deliver_notify 消息推送返回成功就不需要调用这个 api 接口。这个接口用于异常情况推送不成功时手动将单改成已发货状态
- func (s *VirtualPayment) NotifyProvideGoods(ctx context.Context, in *NotifyProvideGoodsRequest) (out *NotifyProvideGoodsResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: notifyProvideGoods,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "NotifyProvideGoods"); err != nil {
- return
- }
- return
- }
- // PresentCurrency 代币赠送接口,由于目前不支付按单号查赠送单的功能,所以当需要赠送的时候可以一直重试到返回 0 或者返回 268490004(重复操作)为止
- func (s *VirtualPayment) PresentCurrency(ctx context.Context, in *PresentCurrencyRequest) (out *PresentCurrencyResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: presentCurrency,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "PresentCurrency"); err != nil {
- return
- }
- return
- }
- // DownloadBill 下载订单交易账单
- func (s *VirtualPayment) DownloadBill(ctx context.Context, in *DownloadBillRequest) (out *DownloadBillResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: downloadBill,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "DownloadBill"); err != nil {
- return
- }
- return
- }
- // RefundOrder 退款 对使用 jsapi 接口下的单进行退款
- func (s *VirtualPayment) RefundOrder(ctx context.Context, in *RefundOrderRequest) (out *RefundOrderResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: refundOrder,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "RefundOrder"); err != nil {
- return
- }
- return
- }
- // CreateWithdrawOrder 创建提现单
- func (s *VirtualPayment) CreateWithdrawOrder(ctx context.Context, in *CreateWithdrawOrderRequest) (out *CreateWithdrawOrderResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: createWithdrawOrder,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "CreateWithdrawOrder"); err != nil {
- return
- }
- return
- }
- // QueryWithdrawOrder 查询提现单
- func (s *VirtualPayment) QueryWithdrawOrder(ctx context.Context, in *QueryWithdrawOrderRequest) (out *QueryWithdrawOrderResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: queryWithdrawOrder,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "QueryWithdrawOrder"); err != nil {
- return
- }
- return
- }
- // StartUploadGoods 开始上传商品
- func (s *VirtualPayment) StartUploadGoods(ctx context.Context, in *StartUploadGoodsRequest) (out *StartUploadGoodsResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: startUploadGoods,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "StartUploadGoods"); err != nil {
- return
- }
- return
- }
- // QueryUploadGoods 查询上传商品
- func (s *VirtualPayment) QueryUploadGoods(ctx context.Context, in *QueryUploadGoodsRequest) (out *QueryUploadGoodsResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: queryUploadGoods,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "QueryUploadGoods"); err != nil {
- return
- }
- return
- }
- // StartPublishGoods 开始发布商品
- func (s *VirtualPayment) StartPublishGoods(ctx context.Context, in *StartPublishGoodsRequest) (out *StartPublishGoodsResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: startPublishGoods,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "StartPublishGoods"); err != nil {
- return
- }
- return
- }
- // QueryPublishGoods 查询发布商品
- func (s *VirtualPayment) QueryPublishGoods(ctx context.Context, in *QueryPublishGoodsRequest) (out *QueryPublishGoodsResponse, err error) {
- var jsonByte []byte
- if jsonByte, err = json.Marshal(in); err != nil {
- return
- }
- var (
- params = URLParams{
- Path: queryPublishGoods,
- Content: string(jsonByte),
- Signature: EmptyString,
- }
- address string
- )
- if address, err = s.requestAddress(params); err != nil {
- return
- }
- var response []byte
- if response, err = util.PostJSONContext(ctx, address, in); err != nil {
- return
- }
- // 使用通用方法返回错误
- if err = util.DecodeWithError(response, out, "QueryPublishGoods"); err != nil {
- return
- }
- return
- }
- // hmacSha256 hmac sha256
- func (s *VirtualPayment) hmacSha256(key, data string) string {
- h := hmac.New(sha256.New, []byte(key))
- h.Write([]byte(data))
- return hex.EncodeToString(h.Sum(nil))
- }
- // PaySign pay sign
- func (s *VirtualPayment) PaySign(url, data string) (string, error) {
- if strings.TrimSpace(s.ctx.Config.AppKey) == "" {
- return "", errors.New("appKey is empty")
- }
- return s.hmacSha256(s.ctx.Config.AppKey, url+"&"+data), nil
- }
- // Signature user signature
- func (s *VirtualPayment) Signature(data string) (string, error) {
- if strings.TrimSpace(s.sessionKey) == "" {
- return "", errors.New("sessionKey is empty")
- }
- return s.hmacSha256(s.sessionKey, data), nil
- }
- // PaySignature pay sign and signature
- func (s *VirtualPayment) PaySignature(url, data string) (paySign, signature string, err error) {
- if paySign, err = s.PaySign(url, data); err != nil {
- return
- }
- if signature, err = s.Signature(data); err != nil {
- return
- }
- return
- }
- // requestURL .组合 URL
- func (s *VirtualPayment) requestAddress(params URLParams) (url string, err error) {
- switch params.Path {
- case queryUserBalance:
- case currencyPay:
- case cancelCurrencyPay:
- if params.PaySign, params.Signature, err = s.PaySignature(params.Path, params.Content); err != nil {
- return
- }
- case queryOrder:
- case notifyProvideGoods:
- case presentCurrency:
- case downloadBill:
- case refundOrder:
- case createWithdrawOrder:
- case queryWithdrawOrder:
- case startUploadGoods:
- case queryUploadGoods:
- case startPublishGoods:
- case queryPublishGoods:
- if params.PaySign, err = s.PaySign(params.Path, params.Content); err != nil {
- return
- }
- default:
- err = errors.New("path is not exist")
- return
- }
- if params.AccessToken, err = s.ctx.GetAccessToken(); err != nil {
- return
- }
- url = baseSite + params.Path + "?" + accessToken + "=" + params.AccessToken
- if params.PaySign != EmptyString {
- url += "&" + paySignature + "=" + params.PaySign
- }
- if params.Signature != EmptyString {
- url += "&" + signature + "=" + params.Signature
- }
- return
- }
|