1
0
mirror of https://github.com/silenceper/wechat.git synced 2026-02-04 12:52:27 +08:00

feat: create mini program virtual payment (#709)

This commit is contained in:
houseme
2023-08-21 22:09:30 +08:00
committed by GitHub
parent 7df3fe1a09
commit 26b0aacb4c
12 changed files with 1216 additions and 27 deletions

View File

@@ -4,7 +4,7 @@
## 包说明
- analysis 数据分析相关API
- analysis 数据分析相关 API
## 快速入门
@@ -18,4 +18,35 @@ cfg := &miniConfig.Config{
}
miniprogram := wc.GetMiniProgram(cfg)
miniprogram.GetAnalysis().GetAnalysisDailyRetain()
```
### 小程序虚拟支付
#### `注意:需要传入 Appkey 的值`
相关文档:[小程序虚拟支付](https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/virtual-payment.html)
```go
wc := wechat.NewWechat()
miniprogram := wc.GetMiniProgram(&miniConfig.Config{
AppID: "xxx",
AppSecret: "xxx",
AppKey: "xxx",
Cache: cache.NewRedis(&redis.Options{
Addr: "",
}),
})
virtualPayment := miniprogram.GetVirtualPayment()
virtualPayment.SetSessionKey("xxx")
// 查询用户余额
var (
res *virtualPayment.QueryUserBalanceResponse
err error
)
if res, err = virtualPayment.QueryUserBalance(context.TODO(), &virtualPayment.QueryUserBalanceRequest{
OpenID: "xxx",
Env: virtualPayment.EnvProduction,
UserIP: "xxx",
}); err != nil {
panic(err)
}
```

View File

@@ -1,4 +1,4 @@
// Package config 小程序config配置
// Package config 小程序 config 配置
package config
import (
@@ -9,5 +9,6 @@ import (
type Config struct {
AppID string `json:"app_id"` // appid
AppSecret string `json:"app_secret"` // appSecret
AppKey string `json:"app_key"` // appKey
Cache cache.Cache
}

View File

@@ -20,15 +20,16 @@ import (
"github.com/silenceper/wechat/v2/miniprogram/tcb"
"github.com/silenceper/wechat/v2/miniprogram/urllink"
"github.com/silenceper/wechat/v2/miniprogram/urlscheme"
"github.com/silenceper/wechat/v2/miniprogram/virtualpayment"
"github.com/silenceper/wechat/v2/miniprogram/werun"
)
// MiniProgram 微信小程序相关API
// MiniProgram 微信小程序相关 API
type MiniProgram struct {
ctx *context.Context
}
// NewMiniProgram 实例化小程序API
// NewMiniProgram 实例化小程序 API
func NewMiniProgram(cfg *config.Config) *MiniProgram {
defaultAkHandle := credential.NewDefaultAccessToken(cfg.AppID, cfg.AppSecret, credential.CacheKeyMiniProgramPrefix, cfg.Cache)
ctx := &context.Context{
@@ -38,7 +39,7 @@ func NewMiniProgram(cfg *config.Config) *MiniProgram {
return &MiniProgram{ctx}
}
// SetAccessTokenHandle 自定义access_token获取方式
// SetAccessTokenHandle 自定义 access_token 获取方式
func (miniProgram *MiniProgram) SetAccessTokenHandle(accessTokenHandle credential.AccessTokenHandle) {
miniProgram.ctx.AccessTokenHandle = accessTokenHandle
}
@@ -68,17 +69,17 @@ func (miniProgram *MiniProgram) GetBusiness() *business.Business {
return business.NewBusiness(miniProgram.ctx)
}
// GetPrivacy 小程序隐私协议相关API
// GetPrivacy 小程序隐私协议相关 API
func (miniProgram *MiniProgram) GetPrivacy() *privacy.Privacy {
return privacy.NewPrivacy(miniProgram.ctx)
}
// GetQRCode 小程序码相关API
// GetQRCode 小程序码相关 API
func (miniProgram *MiniProgram) GetQRCode() *qrcode.QRCode {
return qrcode.NewQRCode(miniProgram.ctx)
}
// GetTcb 小程序云开发API
// GetTcb 小程序云开发 API
func (miniProgram *MiniProgram) GetTcb() *tcb.Tcb {
return tcb.NewTcb(miniProgram.ctx)
}
@@ -103,7 +104,7 @@ func (miniProgram *MiniProgram) GetContentSecurity() *content.Content {
return content.NewContent(miniProgram.ctx)
}
// GetURLLink 小程序URL Link接口
// GetURLLink 小程序 URL Link 接口
func (miniProgram *MiniProgram) GetURLLink() *urllink.URLLink {
return urllink.NewURLLink(miniProgram.ctx)
}
@@ -123,12 +124,17 @@ func (miniProgram *MiniProgram) GetShortLink() *shortlink.ShortLink {
return shortlink.NewShortLink(miniProgram.ctx)
}
// GetSURLScheme 小程序URL Scheme接口
// GetSURLScheme 小程序 URL Scheme 接口
func (miniProgram *MiniProgram) GetSURLScheme() *urlscheme.URLScheme {
return urlscheme.NewURLScheme(miniProgram.ctx)
}
// GetOpenAPI openApi管理接口
// GetOpenAPI openApi 管理接口
func (miniProgram *MiniProgram) GetOpenAPI() *openapi.OpenAPI {
return openapi.NewOpenAPI(miniProgram.ctx)
}
// GetVirtualPayment 小程序虚拟支付
func (miniProgram *MiniProgram) GetVirtualPayment() *virtualpayment.VirtualPayment {
return virtualpayment.NewVirtualPayment(miniProgram.ctx)
}

View File

@@ -24,10 +24,10 @@ func NewShortLink(ctx *context.Context) *ShortLink {
// ShortLinker 请求结构体
type ShortLinker struct {
// pageUrl 通过 Short Link 进入的小程序页面路径,必须是已经发布的小程序存在的页面,可携带 query最大1024个字符
// pageUrl 通过 Short Link 进入的小程序页面路径,必须是已经发布的小程序存在的页面,可携带 query最大 1024 个字符
PageURL string `json:"page_url"`
// pageTitle 页面标题不能包含违法信息超过20字符会用... 截断代替
// pageTitle 页面标题,不能包含违法信息,超过 20 字符会用... 截断代替
PageTitle string `json:"page_title"`
// isPermanent 生成的 Short Link 类型短期有效false永久有效true
@@ -67,7 +67,7 @@ func (shortLink *ShortLink) generate(shortLinkParams ShortLinker) (string, error
return res.Link, nil
}
// GenerateShortLinkPermanent 生成永久shortLink
// GenerateShortLinkPermanent 生成永久 shortLink
func (shortLink *ShortLink) GenerateShortLinkPermanent(PageURL, pageTitle string) (string, error) {
return shortLink.generate(ShortLinker{
PageURL: PageURL,
@@ -76,7 +76,7 @@ func (shortLink *ShortLink) GenerateShortLinkPermanent(PageURL, pageTitle string
})
}
// GenerateShortLinkTemp 生成临时shortLink
// GenerateShortLinkTemp 生成临时 shortLink
func (shortLink *ShortLink) GenerateShortLinkTemp(PageURL, pageTitle string) (string, error) {
return shortLink.generate(ShortLinker{
PageURL: PageURL,

View File

@@ -0,0 +1,134 @@
/*
* 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
const (
// EnvProduction 环境 0-正式环境 1-沙箱环境
EnvProduction Env = 0
// EnvSandbox 环境 0-正式环境 1-沙箱环境
EnvSandbox Env = 1
)
const (
// Success 错误码 0、成功
Success ErrCode = 0
// SystemError 错误码 -1、系统错误
SystemError ErrCode = -1
// OpenIDError 错误码 268490001、openid 错误
OpenIDError ErrCode = 268490001
// RequestParamError 错误码 268490002、请求参数字段错误具体看 errmsg
RequestParamError ErrCode = 268490002
// SignError 错误码 268490003、签名错误
SignError ErrCode = 268490003
// RepeatOperationError 错误码 268490004、重复操作赠送和代币支付相关接口会返回表示之前的操作已经成功
RepeatOperationError ErrCode = 268490004
// OrderRefundedError 错误码 268490005、订单已经通过 cancel_currency_pay 接口退款,不支持再退款
OrderRefundedError ErrCode = 268490005
// InsufficientBalanceError 错误码 268490006、代币的退款/支付操作金额不足
InsufficientBalanceError ErrCode = 268490006
// SensitiveContentError 错误码 268490007、图片或文字存在敏感内容禁止使用
SensitiveContentError ErrCode = 268490007
// TokenNotPublishedError 错误码 268490008、代币未发布不允许进行代币操作
TokenNotPublishedError ErrCode = 268490008
// SessionKeyExpiredError 错误码 268490009、用户 session_key 不存在或已过期,请重新登录
SessionKeyExpiredError ErrCode = 268490009
// BillGeneratingError 错误码 268490011、账单数据生成中请稍后调用本接口获取
BillGeneratingError ErrCode = 268490011
)
const (
// OrderStatusInit 订单状态 当前状态 0-订单初始化(未创建成功,不可用于支付)
OrderStatusInit OrderStatus = 0
// OrderStatusCreated 订单状态 当前状态 1-订单创建成功
OrderStatusCreated OrderStatus = 1
// OrderStatusPaid 订单状态 当前状态 2-订单已经支付,待发货
OrderStatusPaid OrderStatus = 2
// OrderStatusDelivering 订单状态 当前状态 3-订单发货中
OrderStatusDelivering OrderStatus = 3
// OrderStatusDelivered 订单状态 当前状态 4-订单已发货
OrderStatusDelivered OrderStatus = 4
// OrderStatusRefunded 订单状态 当前状态 5-订单已经退款
OrderStatusRefunded OrderStatus = 5
// OrderStatusClosed 订单状态 当前状态 6-订单已经关闭(不可再使用)
OrderStatusClosed OrderStatus = 6
// OrderStatusRefundFailed 订单状态 当前状态 7-订单退款失败
OrderStatusRefundFailed OrderStatus = 7
)
const (
// baseSite 基础网址
baseSite = "https://api.weixin.qq.com"
// queryUserBalance 查询虚拟支付余额
queryUserBalance = "/xpay/query_user_balance"
// currencyPay 扣减代币(一般用于代币支付)
currencyPay = "/xpay/currency_pay"
// queryOrder 查询创建的订单(现金单,非代币单)
queryOrder = "/xpay/query_order"
// cancelCurrencyPay 代币支付退款 (currency_pay 接口的逆操作)
cancelCurrencyPay = "/xpay/cancel_currency_pay"
// notifyProvideGoods 通知已经发货完成(只能通知现金单),正常通过 xpay_goods_deliver_notify 消息推送返回成功就不需要调用这个 api 接口。这个接口用于异常情况推送不成功时手动将单改成已发货状态
notifyProvideGoods = "/xpay/notify_provide_goods"
// presentCurrency 代币赠送接口,由于目前不支付按单号查赠送单的功能,所以当需要赠送的时候可以一直重试到返回 0 或者返回 268490004重复操作为止
presentCurrency = "/xpay/present_currency"
// downloadBill 下载账单
downloadBill = "/xpay/download_bill"
// refundOrder 退款 对使用 jsapi 接口下的单进行退款
refundOrder = "/xpay/refund_order"
// createWithdrawOrder 创建提现单
createWithdrawOrder = "/xpay/create_withdraw_order"
// queryWithdrawOrder 查询提现单
queryWithdrawOrder = "/xpay/query_withdraw_order"
// startUploadGoods 启动批量上传道具任务
startUploadGoods = "/xpay/start_upload_goods"
// queryUploadGoods 查询批量上传道具任务状态
queryUploadGoods = "/xpay/query_upload_goods"
// startPublishGoods 启动批量发布道具任务
startPublishGoods = "/xpay/start_publish_goods"
// queryPublishGoods 查询批量发布道具任务状态
queryPublishGoods = "/xpay/query_publish_goods"
)
const (
// signature user mode signature
signature = "signature"
// paySignature payment signature
paySignature = "pay_sig"
// accessToken access_token authorization tokens
accessToken = "access_token"
// EmptyString empty string
EmptyString = ""
)

View File

@@ -0,0 +1,32 @@
/*
* 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 mini program virtual payment
package virtualpayment
import (
"github.com/silenceper/wechat/v2/miniprogram/context"
)
// NewVirtualPayment 实例化小程序虚拟支付 API
func NewVirtualPayment(ctx *context.Context) *VirtualPayment {
return &VirtualPayment{
ctx: ctx,
}
}

View File

@@ -0,0 +1,427 @@
/*
* 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 (
"github.com/silenceper/wechat/v2/miniprogram/context"
"github.com/silenceper/wechat/v2/util"
)
// VirtualPayment mini program virtual payment
// https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/virtual-payment.html#_2-3-%E6%9C%8D%E5%8A%A1%E5%99%A8API
type VirtualPayment struct {
ctx *context.Context
sessionKey string
}
// Env Environment 0 - Production environment 1 - Sandbox environment
type Env int
// ErrCode error code
type ErrCode int
// OrderStatus 订单状态
type OrderStatus int
// CommonRequest common request parameters
type CommonRequest struct {
OpenID string `json:"openid"` // The user's openID
Env Env `json:"env"` // Environment 0 - Production environment 1 - Sandbox environment
}
// PaymentRequest payment request parameters
type PaymentRequest struct {
SignData string `json:"sign_data"` // 具体支付参数见 signData, 该参数需以 string 形式传递,例如 signData: '{"offerId":"123","buyQuantity":1,"env":0,"currencyType":"CNY","platform":"android","productId":"testproductId","goodsPrice":10,"outTradeNo":"xxxxxx","attach":"testdata"}'
Mode string `json:"mode"` // 支付模式枚举值short_series_goods: 道具直购short_series_coin: 代币充值
PaySig string `json:"pay_sig"` // 支付签名,具体生成方式见下方说明
Signature string `json:"signature"` // 用户态签名,具体生成方式见下方说明
}
// SignData 签名数据
type SignData struct {
OfferID string `json:"offerId"` // 在米大师侧申请的应用 id, mp-支付基础配置中的 offerid
BuyQuantity int `json:"buyQuantity"` // 购买数量
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
CurrencyType string `json:"currencyType"` // 币种 默认值CNY 人民币
Platform string `json:"platform,omitempty"` // 申请接入时的平台platform 与应用 id 有关 默认值android 安卓平台
ProductID string `json:"productId,omitempty"` // 道具 ID, **该字段仅 mode=short_series_goods 时可用**
GoodsPrice int `json:"goodsPrice"` // 道具单价 (分), **该字段仅 mode=short_series_goods 时可用**, 用来校验价格与后台道具价格是否一致,避免用户在业务商城页看到的价格与实际价格不一致导致投诉
OutTradeNo string `json:"outTradeNo"` // 业务订单号,每个订单号只能使用一次,重复使用会失败 (极端情况不保证唯一,不建议业务强依赖唯一性). 要求 8-32 个字符内,只能是数字、大小写字母、符号 _-|*@组成,不能以下划线 (_) 开头
Attach string `json:"attach"` // 透传数据,发货通知时会透传给开发者
}
// QueryUserBalanceRequest 查询用户代币余额,请求参数
// 1. 需要用户态签名与支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type QueryUserBalanceRequest struct {
CommonRequest
UserIP string `json:"user_ip"` // 用户 ip例如:1.1.1.1
}
// QueryUserBalanceResponse 查询虚拟支付余额 响应参数
type QueryUserBalanceResponse struct {
util.CommonError
Balance int `json:"balance"` // 代币总余额,包括有价和赠送部分
PresentBalance int `json:"present_balance"` // 赠送账户的代币余额
SumSave int `json:"sum_save"` // 累计有价货币充值数量
SumPresent int `json:"sum_present"` // 累计赠送无价货币数量
SumBalance int `json:"sum_balance"` // 历史总增加的代币金额
SumCost int `json:"sum_cost"` // 历史总消耗代币金额
FirstSaveFlag int `json:"first_save_flag"` // 是否满足首充活动标记。0:不满足。1:满足
}
// CurrencyPayRequest 扣减代币(一般用于代币支付)
// 1. 需要用户态签名与支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type CurrencyPayRequest struct {
CommonRequest
UserIP string `json:"user_ip"` // 用户 ip例如1.1.1.1
Amount int `json:"amount"` // 支付的代币数量
OrderID string `json:"order_id"` // 商户订单号,需要保证唯一性
PayItem string `json:"payitem"` // 物品信息。记录到账户流水中。如:[{"productid":"物品 id", "unit_price": 单价,"quantity": 数量}]
Remark string `json:"remark"` // 备注信息。需要在账单中展示
DeviceType string `json:"device_type"` // 平台类型 1-安卓 2-苹果
}
// PayItem 物品信息
type PayItem struct {
ProductID string `json:"productid"` // 物品 id
UnitPrice int `json:"unit_price"` // 单价
Quantity int `json:"quantity"` // 数量
}
// CurrencyPayResponse 扣减代币(一般用于代币支付)响应参数
type CurrencyPayResponse struct {
util.CommonError
OrderID string `json:"order_id"` // 商户订单号
Balance int `json:"balance"` // 总余额,包括有价和赠送部分
UsedPresentAmount int `json:"used_present_amount"` // 使用赠送部分的代币数量
}
// QueryOrderRequest 查询创建的订单(现金单,非代币单),请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type QueryOrderRequest struct {
CommonRequest
OrderID string `json:"order_id,omitempty"` // 商户订单号 创建的订单号
WxOrderID string `json:"wx_order_id,omitempty"` // 微信内部单号 (与 order_id 二选一)
}
// OrderItem 订单信息
type OrderItem struct {
OrderID string `json:"order_id"` // 商户订单号
CreateTime int64 `json:"create_time"` // 订单创建时间
UpdateTime int64 `json:"update_time"` // 订单更新时间
Status OrderStatus `json:"status"` // 订单状态 当前状态 0-订单初始化未创建成功不可用于支付1-订单创建成功 2-订单已经支付,待发货 3-订单发货中 4-订单已发货 5-订单已经退款 6-订单已经关闭不可再使用7-订单退款失败
BizType int `json:"biz_type"` // 业务类型 0-短剧
OrderFee int `json:"order_fee"` // 订单金额,单位:分
CouponFee int `json:"coupon_fee"` // 优惠金额,单位:分
PaidFee int `json:"paid_fee"` // 用户支付金额,单位:分
OrderType int `json:"order_type"` // 订单类型 0-支付单 1-退款单
RefundFee int `json:"refund_fee"` // 当类型为退款单时表示退款金额,单位分
PaidTime int64 `json:"paid_time"` // 支付/退款时间unix秒级时间戳
ProvideTime int64 `json:"provide_time"` // 发货时间unix 秒级时间戳
BizMeta string `json:"biz_meta"` // 业务自定义数据 订单创建时传的信息
EnvType int `json:"env_type"` // 环境类型 1-现网 2-沙箱
Token string `json:"token"` // 下单时米大师返回的 token
LeftFee int `json:"left_fee"` // 支付单类型时表示此单经过退款还剩余的金额,单位:分
WxOrderID string `json:"wx_order_id"` // 微信内部单号
ChannelOrderID string `json:"channel_order_id"` // 渠道订单号,为用户微信支付详情页面上的商户单号
WxPayOrderID string `json:"wxpay_order_id"` // 微信支付交易单号,为用户微信支付详情页面上的交易单号
}
// QueryOrderResponse 查询创建的订单(现金单,非代币单)响应参数
type QueryOrderResponse struct {
util.CommonError
Order *OrderItem `json:"order"` // 订单信息
}
// CancelCurrencyPayRequest 取消订单(现金单,非代币单),请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type CancelCurrencyPayRequest struct {
CommonRequest
UserIP string `json:"user_ip"` // 用户 ip例如1.1.1.1
PayOrderID string `json:"pay_order_id"` // 支付单号 代币支付 (调用 currency_pay 接口时) 时传的 order_id
OrderID string `json:"order_id"` // 本次退款单的单号
Amount int `json:"amount"` // 退款金额
DeviceType int `json:"device_type"` // 平台类型 1-安卓 2-苹果
}
// CancelCurrencyPayResponse 取消订单(现金单,非代币单)响应参数
type CancelCurrencyPayResponse struct {
util.CommonError
OrderID string `json:"order_id"` // 退款订单号
}
// NotifyProvideGoodsRequest 通知发货,请求参数
// 通知已经发货完成(只能通知现金单),正常通过 xpay_goods_deliver_notify 消息推送返回成功就不需要调用这个 api 接口。这个接口用于异常情况推送不成功时手动将单改成已发货状态
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type NotifyProvideGoodsRequest struct {
OrderID string `json:"order_id,omitempty"` // 商户订单号 下单时传的单号
WxOrderID string `json:"wx_order_id,omitempty"` // 微信内部单号 (与 order_id 二选一)
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
}
// NotifyProvideGoodsResponse 通知发货响应参数
type NotifyProvideGoodsResponse struct {
util.CommonError
}
// PresentCurrencyRequest 赠送代币,请求参数
// 代币赠送接口,由于目前不支付按单号查赠送单的功能,所以当需要赠送的时候可以一直重试到返回 0 或者返回 268490004重复操作为止
// 1. 需要用户态签名与支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type PresentCurrencyRequest struct {
CommonRequest
OrderID string `json:"order_id"` // 赠送单号,商户订单号,需要保证唯一性
Amount int `json:"amount"` // 赠送的代币数量
DeviceType string `json:"device_type"` // 平台类型 1-安卓 2-苹果
}
// PresentCurrencyResponse 赠送代币响应参数
type PresentCurrencyResponse struct {
util.CommonError
Balance int `json:"balance"` // 赠送后用户的代币余额
OrderID string `json:"order_id"` // 赠送单号
PresentBalance int `json:"present_balance"` // 用户收到的总赠送金额
}
// DownloadBillRequest 下载账单,请求参数
// 用于下载小程序账单,第一次调用触发生成下载 url可以间隔轮训来获取最终生成的下载 url。账单中金额相关字段是以分为单位。
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type DownloadBillRequest struct {
BeginDs string `json:"begin_ds"` // 账单开始日期,格式为 yyyymmdd 起始时间(如 20230801
EndDs string `json:"end_ds"` // 账单结束日期,格式为 yyyymmdd 结束时间(如 20230801
}
// DownloadBillResponse 下载账单响应参数
type DownloadBillResponse struct {
util.CommonError
URL string `json:"url"` // 账单下载地址
}
// RefundOrderRequest 退款,请求参数
// 对使用 jsapi 接口下的单进行退款
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type RefundOrderRequest struct {
CommonRequest
OrderID string `json:"order_id"` // 商户订单号,需要保证唯一性
WxOrderID string `json:"wx_order_id"` // 微信内部单号 (与 order_id 二选一)
RefundOrderID string `json:"refund_order_id"` // 退款单号,本次退款时需要传的单号,长度为 [8,32],字符只允许使用字母、数字、'_'、'-'
LeftFee int `json:"left_fee"` // 退款金额,单位:分 当前单剩余可退金额,单位分,可以通过调用 query_order 接口查到
RefundFee int `json:"refund_fee"` // 退款金额,单位:分 需要 (0,left_fee] 之间
BizMeta string `json:"biz_meta"` // 商家自定义数据,传入后可在 query_order 接口查询时原样返回,长度需要 [0,1024]
RefundReason string `json:"refund_reason"` // 退款原因,当前仅支持以下值 0-暂无描述 1-产品问题,影响使用或效果不佳 2-售后问题,无法满足需求 3-意愿问题,用户主动退款 4-价格问题 5:其他原因
ReqFrom string `json:"req_from"` // 退款来源,当前仅支持以下值 1-人工客服退款,即用户电话给客服,由客服发起退款流程 2-用户自己发起退款流程 3-其它
}
// RefundOrderResponse 退款响应参数
type RefundOrderResponse struct {
util.CommonError
RefundOrderID string `json:"refund_order_id"` // 退款单号
RefundWxOrderID string `json:"refund_wx_order_id"` // 退款单的微信侧单号
PayOrderID string `json:"pay_order_id"` // 该退款单对应的支付单单号
PayWxOrderID string `json:"pay_wx_order_id"` // 该退款单对应的支付单微信侧单号
}
// CreateWithdrawOrderRequest 创建提现单,请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type CreateWithdrawOrderRequest struct {
WithdrawNO string `json:"withdraw_no"` // 提现单单号,长度为 [8,32],字符只允许使用字母、数字、'_'、'-'
WithdrawAmount string `json:"withdraw_amount"` // 提现的金额,单位元,例如提现 1 分钱请使用 0.01
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
}
// CreateWithdrawOrderResponse 创建提现单响应参数
type CreateWithdrawOrderResponse struct {
util.CommonError
WithdrawNO string `json:"withdraw_no"` // 提现单单号
WxWithdrawNO string `json:"wx_withdraw_no"` // 提现单的微信侧单号
}
// QueryWithdrawOrderRequest 查询提现单,请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type QueryWithdrawOrderRequest struct {
WithdrawNO string `json:"withdraw_no"` // 提现单单号,长度为 [8,32],字符只允许使用字母、数字、'_'、'-' (与 wx_withdraw_no 二选一)
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
}
// QueryWithdrawOrderResponse 查询提现单响应参数
type QueryWithdrawOrderResponse struct {
util.CommonError
WithdrawNO string `json:"withdraw_no"` // 提现单单号
Status int `json:"status"` // 提现单的微信侧单号 1-创建成功,提现中 2-提现成功 3-提现失败
WithdrawAmount string `json:"withdraw_amount"` // 提现的金额,单位元,例如提现 1 分钱请使用 0.01
WxWithdrawNo string `json:"wx_withdraw_no"` // 提现单的微信侧单号
WithdrawSuccessTimestamp int64 `json:"withdraw_success_timestamp"` // 提现单成功的秒级时间戳unix 秒级时间戳
CreateTime string `json:"create_time"` // 提现单创建时间
FailReason string `json:"failReason"` // 提现失败的原因
}
// StartUploadGoodsRequest 启动批量上传道具任务,请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type StartUploadGoodsRequest struct {
UploadItem []*UploadItem `json:"upload_item"` // 道具信息
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
}
// UploadItem 道具信息
type UploadItem struct {
ID string `json:"id"` // 道具 id长度 (0,64],字符只允许使用字母、数字、'_'、'-'
Name string `json:"name"` // 道具名称,长度 (0,1024]
Price int `json:"price"` // 道具单价,单位分,需要大于 0
Remark string `json:"remark"` // 道具备注,长度 (0,1024]
ItemURL string `json:"item_url"` // 道具图片的 url 地址,当前仅支持 jpg,png 等格式
UploadStatus int `json:"upload_status,omitempty"` // 上传状态 0-上传中 1-id 已经存在 2-上传成功 3-上传失败
ErrMsg string `json:"errmsg,omitempty"` // 上传失败的原因
}
// StartUploadGoodsResponse 启动批量上传道具任务响应参数
type StartUploadGoodsResponse struct {
util.CommonError
}
// QueryUploadGoodsRequest 查询批量上传道具任务,请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type QueryUploadGoodsRequest struct {
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
}
// QueryUploadGoodsResponse 查询批量上传道具任务响应参数
type QueryUploadGoodsResponse struct {
util.CommonError
UploadItem []*UploadItem `json:"upload_item"` // 道具信息列表
Status int `json:"status"` // 任务状态 0-无任务在运行 1-任务运行中 2-上传失败或部分失败上传任务已经完成3-上传成功
}
// StartPublishGoodsRequest 启动批量发布道具任务,请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type StartPublishGoodsRequest struct {
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
PublishItem []*PublishItem `json:"publish_item"` // 道具信息 发布的商品列表
}
// PublishItem 道具信息
type PublishItem struct {
ID string `json:"id"` // 道具 id添加到开发环境时传的道具 id长度 (0,64],字符只允许使用字母、数字、'_'、'-'
PublishStatus int `json:"publish_status,omitempty"` // 发布状态 0-上传中 1-id 已经存在 2-发布成功 3-发布失败
ErrMsg string `json:"errmsg,omitempty"` // 发布失败的原因
}
// StartPublishGoodsResponse 启动批量发布道具任务响应参数
type StartPublishGoodsResponse struct {
util.CommonError
}
// QueryPublishGoodsRequest 查询批量发布道具任务,请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type QueryPublishGoodsRequest struct {
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
}
// QueryPublishGoodsResponse 查询批量发布道具任务响应参数
type QueryPublishGoodsResponse struct {
util.CommonError
PublishItem []*PublishItem `json:"publish_item"` // 道具信息列表
Status int `json:"status"` // 任务状态 0-无任务在运行 1-任务运行中 2-上传失败或部分失败上传任务已经完成3-上传成功
}
// AsyncXPayGoodsDeliverNotifyRequest 异步通知发货,请求参数
// 1. 使用支付签名
// POST请求参数为 json 字符串Content-Type 为 application/json
type AsyncXPayGoodsDeliverNotifyRequest struct {
ToUserName string `json:"ToUserName"` // 小程序的原始 ID
FromUserName string `json:"FromUserName"` // 发送方帐号(一个 OpenID该事件消息的 openid道具发货场景固定为微信官方的 openid
CreateTime int `json:"CreateTime"` // 消息发送时间(整型)
MsgType string `json:"MsgType"` // 消息类型此时固定为event
Event string `json:"Event"` // 事件类型此时固定为xpay_goods_deliver_notify
Openid string `json:"openid"` // 用户 openid
OutTradeNo string `json:"OutTradeNo"` // 业务订单号
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
WechatPayInfo *WeChatPayInfo `json:"WechatPayInfo"` // 微信支付订单信息
GoodsInfo *GoodsInfo `json:"GoodsInfo"` // 道具信息
}
// WeChatPayInfo 微信支付信息 非微信支付渠道可能没有
type WeChatPayInfo struct {
MchOrderNo string `json:"MchOrderNo"` // 商户订单号
TransactionID string `json:"TransactionId"` // 微信支付订单号
}
// GoodsInfo 道具参数信息
type GoodsInfo struct {
ProductID string `json:"ProductId"` // 道具 ID
Quantity int `json:"Quantity"` // 数量
OrigPrice int `json:"OrigPrice"` // 物品原始价格(单位:分)
ActualPrice int `json:"ActualPrice"` // 物品实际支付价格(单位:分)
Attach string `json:"Attach"` // 透传信息
}
// AsyncXPayGoodsDeliverNotifyResponse 异步通知发货响应参数
type AsyncXPayGoodsDeliverNotifyResponse struct {
util.CommonError
}
// AsyncXPayCoinPayNotifyRequest 异步通知代币支付推送,请求参数
type AsyncXPayCoinPayNotifyRequest struct {
ToUserName string `json:"ToUserName"` // 小程序的原始 ID
FromUserName string `json:"FromUserName"` // 发送方帐号(一个 OpenID该事件消息的 openid道具发货场景固定为微信官方的 openid
CreateTime int `json:"CreateTime"` // 消息发送时间(整型)
MsgType string `json:"MsgType"` // 消息类型此时固定为event
Event string `json:"Event"` // 事件类型此时固定为xpay_goods_deliver_notify
Openid string `json:"openid"` // 用户 openid
OutTradeNo string `json:"OutTradeNo"` // 业务订单号
Env Env `json:"env"` // 环境 0-正式环境 1-沙箱环境
WechatPayInfo *WeChatPayInfo `json:"WechatPayInfo"` // 微信支付订单信息
CoinInfo *CoinInfo `json:"GoodsInfo"` // 道具信息
}
// CoinInfo 代币信息
type CoinInfo struct {
Quantity int `json:"Quantity"` // 数量
OrigPrice int `json:"OrigPrice"` // 物品原始价格(单位:分)
ActualPrice int `json:"ActualPrice"` // 物品实际支付价格(单位:分)
Attach string `json:"Attach"` // 透传信息
}
// AsyncXPayCoinPayNotifyResponse 异步通知代币支付推送响应参数
type AsyncXPayCoinPayNotifyResponse struct {
util.CommonError
}
// URLParams url parameter
type URLParams struct {
Path string `json:"path"`
AccessToken string `json:"access_token"`
PaySign string `json:"paySign"`
Signature string `json:"signature"`
Content string `json:"content"`
}

View File

@@ -0,0 +1,558 @@
/*
* 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
}

View File

@@ -27,7 +27,7 @@ const (
PermanentMaterialTypeImage PermanentMaterialType = "image"
// PermanentMaterialTypeVideo 永久素材视频类型video
PermanentMaterialTypeVideo PermanentMaterialType = "video"
// PermanentMaterialTypeVoice 永久素材语音类型 voice
// PermanentMaterialTypeVoice 永久素材语音类型voice
PermanentMaterialTypeVoice PermanentMaterialType = "voice"
// PermanentMaterialTypeNews 永久素材图文类型news
PermanentMaterialTypeNews PermanentMaterialType = "news"
@@ -278,7 +278,7 @@ type ArticleList struct {
Item []ArticleListItem `json:"item"`
}
// ArticleListItem 用于ArticleListitem节点
// ArticleListItem 用于 ArticleListitem 节点
type ArticleListItem struct {
MediaID string `json:"media_id"`
Content ArticleListContent `json:"content"`
@@ -287,14 +287,14 @@ type ArticleListItem struct {
UpdateTime int64 `json:"update_time"`
}
// ArticleListContent 用于ArticleListItemcontent节点
// ArticleListContent 用于 ArticleListItemcontent 节点
type ArticleListContent struct {
NewsItem []Article `json:"news_item"`
UpdateTime int64 `json:"update_time"`
CreateTime int64 `json:"create_time"`
}
// reqBatchGetMaterial BatchGetMaterial请求参数
// reqBatchGetMaterial BatchGetMaterial 请求参数
type reqBatchGetMaterial struct {
Type PermanentMaterialType `json:"type"`
Count int64 `json:"count"`
@@ -337,7 +337,7 @@ type ResMaterialCount struct {
NewsCount int64 `json:"news_count"` // 图文总数量
}
// GetMaterialCount 获取素材总数.
// GetMaterialCount 获取素材总数
func (material *Material) GetMaterialCount() (res ResMaterialCount, err error) {
var accessToken string
accessToken, err = material.GetAccessToken()

View File

@@ -6,7 +6,7 @@ import (
"reflect"
)
// CommonError 微信返回的通用错误json
// CommonError 微信返回的通用错误 json
type CommonError struct {
apiName string
ErrCode int64 `json:"errcode"`
@@ -17,7 +17,7 @@ func (c *CommonError) Error() string {
return fmt.Sprintf("%s Error , errcode=%d , errmsg=%s", c.apiName, c.ErrCode, c.ErrMsg)
}
// NewCommonError 新建CommonError错误对于无errcodeerrmsg的返回也可以返回该通用错误
// NewCommonError 新建 CommonError 错误,对于无 errcodeerrmsg 的返回也可以返回该通用错误
func NewCommonError(apiName string, code int64, msg string) *CommonError {
return &CommonError{
apiName: apiName,
@@ -26,7 +26,7 @@ func NewCommonError(apiName string, code int64, msg string) *CommonError {
}
}
// DecodeWithCommonError 将返回值按照CommonError解析
// DecodeWithCommonError 将返回值按照 CommonError 解析
func DecodeWithCommonError(response []byte, apiName string) (err error) {
var commError CommonError
err = json.Unmarshal(response, &commError)

View File

@@ -100,7 +100,7 @@ func PostJSON(uri string, obj interface{}) ([]byte, error) {
return PostJSONContext(context.Background(), uri, obj)
}
// PostJSONWithRespContentType post json数据请求且返回数据类型
// PostJSONWithRespContentType post json 数据请求,且返回数据类型
func PostJSONWithRespContentType(uri string, obj interface{}) ([]byte, string, error) {
jsonBuf := new(bytes.Buffer)
enc := json.NewEncoder(jsonBuf)
@@ -216,7 +216,7 @@ func PostXML(uri string, obj interface{}) ([]byte, error) {
return io.ReadAll(response.Body)
}
// httpWithTLS CA证书
// httpWithTLS CA 证书
func httpWithTLS(rootCa, key string) (*http.Client, error) {
var client *http.Client
certData, err := os.ReadFile(rootCa)
@@ -235,7 +235,7 @@ func httpWithTLS(rootCa, key string) (*http.Client, error) {
return client, nil
}
// pkcs12ToPem 将Pkcs12转成Pem
// pkcs12ToPem 将 Pkcs12 转成 Pem
func pkcs12ToPem(p12 []byte, password string) tls.Certificate {
blocks, err := pkcs12.ToPEM(p12, password)
defer func() {

View File

@@ -40,7 +40,7 @@ func NewWechat() *Wechat {
return &Wechat{}
}
// SetCache 设置cache
// SetCache 设置 cache
func (wc *Wechat) SetCache(cache cache.Cache) {
wc.cache = cache
}