Skip to content

Commit

Permalink
v1.5.40
Browse files Browse the repository at this point in the history
  • Loading branch information
iGoogle-ink committed Jun 1, 2021
1 parent d6dbac1 commit 2618339
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 17 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# GoPay

#### QQ、微信、支付宝的Golang版本SDK

[![Github](https://img.shields.io/github/followers/iGoogle-ink?label=Follow&style=social)](https://github.com/iGoogle-ink)
[![Github](https://img.shields.io/github/forks/iGoogle-ink/gopay?label=Fork&style=social)](https://github.com/iGoogle-ink/gopay/fork)

Expand Down Expand Up @@ -80,9 +81,13 @@ func main() {
* 商户发起催收扣款:client.V3ScoreOrderPay()
* 同步服务订单信息:client.V3ScoreOrderSync()
* <font color='#07C160' size='4'>微信支付分(免确认模式)</font>
* 待实现
* 创单结单合并:client.V3ScoreDirectComplete()
* <font color='#07C160' size='4'>微信支付分(免确认预授权模式)</font>
* 待实现
* 商户预授权:client.V3ScorePermission()
* 查询用户授权记录(授权协议号):client.V3ScorePermissionQuery()
* 解除用户授权关系(授权协议号):client.V3ScorePermissionTerminate()
* 查询用户授权记录(openid):client.V3ScorePermissionOpenidQuery()
* 解除用户授权关系(openid):client.V3ScorePermissionOpenidTerminate()
* <font color='#07C160' size='4'>微信先享卡</font>
* 待实现
* <font color='#07C160' size='4'>支付即服务</font>
Expand All @@ -105,6 +110,7 @@ func main() {
* 图片上传(营销专用):
* 图片上传:
* 视频上传:

### 微信支付V2 API

> #### 推荐使用V3接口,官方在V3接口实现未覆盖或gopay未开发的接口,还继续用V2接口。
Expand Down
2 changes: 1 addition & 1 deletion constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const (
OK = "OK"
DebugOff = 0
DebugOn = 1
Version = "1.5.39"
Version = "1.5.40"
)

type DebugSwitch int8
5 changes: 5 additions & 0 deletions release_note.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
版本号:Release 1.5.40
修改记录:
(1) 微信V3:新增微信支付分(免确认模式)相关接口
(2) 微信V3:新增微信支付分(免确认预授权模式)相关接口

版本号:Release 1.5.39
修改记录:
(1) 微信V3:新增微信支付分(公共API)相关接口
Expand Down
2 changes: 1 addition & 1 deletion wechat/v3/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type ClientV3 struct {
// mchid:商户ID 或者服务商模式的 sp_mchid
// serialNo:商户证书的证书序列号
// apiV3Key:apiV3Key,商户平台获取
// pkContent:私钥 apiclient_key.pem 读取后的内容
// pkContent:私钥 apiclient_key.pem 读取后的字符串内容
func NewClientV3(appid, mchid, serialNo, apiV3Key, pkContent string) (client *ClientV3, err error) {
var (
pk *rsa.PrivateKey
Expand Down
2 changes: 1 addition & 1 deletion wechat/v3/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestMain(m *testing.M) {
// mchid:商户ID
// serialNo:商户证书的证书序列号
// apiV3Key:apiV3Key,商户平台获取
// pkContent:私钥 apiclient_key.pem 读取后的内容
// pkContent:私钥 apiclient_key.pem 读取后的字符串内容
client, err = NewClientV3(Appid, MchId, SerialNo, ApiV3Key, PKContent)
if err != nil {
xlog.Error(err)
Expand Down
16 changes: 9 additions & 7 deletions wechat/v3/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,15 @@ const (
v3ApiFundFlowBill = "/v3/bill/fundflowbill" // 申请资金账单
v3ApiLevel2FundFlowBill = "/v3/ecommerce/bill/fundflowbill" // 申请二级商户资金账单

// 微信支付分
v3ScorePermission = "/v3/payscore/permissions" // 商户预授权 POST
v3ScorePermissionAuthorizationQuery = "/v3/payscore/permissions/authorization-code/%s" // authorization_code 查询用户授权记录(授权协议号) GET
v3ScorePermissionAuthorizationTerminate = "/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
v3ScoreOrderDirectComplete = "/payscore/serviceorder/direct-complete" // 创单结单合并 POST
// 微信支付分(免确认模式)
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
Expand Down
91 changes: 91 additions & 0 deletions wechat/v3/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,52 @@ type ScoreOrderSyncRsp struct {
Error string `json:"-"`
}

// 创单结单合并 Rsp
type ScoreDirectCompleteRsp struct {
Code int `json:"-"`
SignInfo *SignInfo `json:"-"`
Response *ScoreDirectComplete `json:"response,omitempty"`
Error string `json:"-"`
}

// 创单结单合并 Rsp
type ScorePermissionRsp struct {
Code int `json:"-"`
SignInfo *SignInfo `json:"-"`
Response *ScorePermission `json:"response,omitempty"`
Error string `json:"-"`
}

// 查询用户授权记录(授权协议号) Rsp
type ScorePermissionQueryRsp struct {
Code int `json:"-"`
SignInfo *SignInfo `json:"-"`
Response *ScorePermissionQuery `json:"response,omitempty"`
Error string `json:"-"`
}

// 解除用户授权关系(授权协议号) Rsp
type ScorePermissionTerminateRsp struct {
Code int `json:"-"`
SignInfo *SignInfo `json:"-"`
Error string `json:"-"`
}

// 查询用户授权记录(openid) Rsp
type ScorePermissionOpenidQueryRsp struct {
Code int `json:"-"`
SignInfo *SignInfo `json:"-"`
Response *ScorePermissionOpenidQuery `json:"response,omitempty"`
Error string `json:"-"`
}

// 解除用户授权关系(openid) Rsp
type ScorePermissionOpenidTerminateRsp struct {
Code int `json:"-"`
SignInfo *SignInfo `json:"-"`
Error string `json:"-"`
}

// ==================================分割==================================

type JSAPIPayParams struct {
Expand Down Expand Up @@ -589,3 +635,48 @@ type ScoreOrderSync struct {
Collection *Collection `json:"collection,omitempty"` // 收款信息
Openid string `json:"openid"` // 微信用户在商户对应appid下的唯一标识
}

type ScoreDirectComplete struct {
Appid string `json:"appid"` // 调用接口提交的公众账号ID。
Mchid string `json:"mchid"` // 调用接口提交的商户号。
OutTradeNo string `json:"out_trade_no"` // 调用接口提交的商户服务订单号。
ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。
OrderId string `json:"order_id"` // 微信支付服务订单号,每个微信支付服务订单号与商户号下对应的商户服务订单号一一对应。
ServiceIntroduction string `json:"service_introduction"` // 服务信息,用于介绍本订单所提供的服务。
State string `json:"state"` // 表示当前单据状态。枚举值:CREATED:商户已创建服务订单,DOING:服务订单进行中,DONE:服务订单完成,REVOKED:商户取消服务订单,EXPIRED:服务订单已失效
StateDescription string `json:"state_description,omitempty"` // 对服务订单"进行中"状态的附加说明。USER_CONFIRM:用户确认,MCH_COMPLETE:商户完结
PostPayments []*PostPayments `json:"post_payments"` // 后付费项目列表,最多包含100条付费项目。 如果传入,用户侧则显示此参数。
PostDiscounts []*PostDiscounts `json:"post_discounts,omitempty"` // 后付费商户优惠,最多包含30条付费项目。 如果传入,用户侧则显示此参数。
TimeRange *TimeRange `json:"time_range"` // 服务时间范围
Location *Location `json:"location,omitempty"` // 服务位置信息
Attach string `json:"attach,omitempty"` // 商户数据包,可存放本订单所需信息,需要先urlencode后传入,总长度不大于256字符,超出报错处理。
NotifyUrl string `json:"notify_url,omitempty"` // 商户接收用户确认订单或扣款成功回调通知的地址。
TotalAmount int `json:"total_amount"` // 金额:数字,必须≥0(单位:分)
}

type ScorePermission struct {
ApplyPermissionsToken string `json:"apply_permissions_token"` // 用于跳转到微信侧小程序授权数据,跳转到微信侧小程序传入,时效性为1小时
}

type ScorePermissionQuery struct {
Appid string `json:"appid"` // 调用接口提交的公众账号ID。
Mchid string `json:"mchid"` // 调用接口提交的商户号。
ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。
Openid string `json:"openid,omitempty"` // 微信用户在商户对应appid下的唯一标识
AuthorizationCode string `json:"authorization_code"` // 预授权成功时的授权协议号。
AuthorizationState string `json:"authorization_state"` // 标识用户授权服务情况:UNAVAILABLE:用户未授权服务,AVAILABLE:用户已授权服务,UNBINDUSER:未绑定用户(已经预授权但未完成正式授权)
NotifyUrl string `json:"notify_url,omitempty"` // 商户接收用户确认订单或扣款成功回调通知的地址。
CancelAuthorizationTime string `json:"cancel_authorization_time,omitempty"` // 最近一次解除授权时间, 示例值:2015-05-20T13:29:35.120+08:00
AuthorizationSuccessTime string `json:"authorization_success_time"` // 最近一次授权成功时间, 示例值:2015-05-20T13:29:35.120+08:00
}

type ScorePermissionOpenidQuery struct {
Appid string `json:"appid"` // 调用接口提交的公众账号ID。
Mchid string `json:"mchid"` // 调用接口提交的商户号。
ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。
Openid string `json:"openid,omitempty"` // 微信用户在商户对应appid下的唯一标识
AuthorizationCode string `json:"authorization_code"` // 预授权成功时的授权协议号。
AuthorizationState string `json:"authorization_state"` // 标识用户授权服务情况:UNAVAILABLE:用户未授权服务,AVAILABLE:用户已授权服务,UNBINDUSER:未绑定用户(已经预授权但未完成正式授权)
CancelAuthorizationTime string `json:"cancel_authorization_time,omitempty"` // 最近一次解除授权时间, 示例值:2015-05-20T13:29:35.120+08:00
AuthorizationSuccessTime string `json:"authorization_success_time"` // 最近一次授权成功时间, 示例值:2015-05-20T13:29:35.120+08:00
}
172 changes: 167 additions & 5 deletions wechat/v3/score_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,168 @@ import (
"github.com/iGoogle-ink/gopay/pkg/util"
)

// 创单结单合并API
// Code = 0 is success
// 注意:限制条件:【免确认订单模式】,用户已授权状态下,可调用该接口。
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_1.shtml
func (c *ClientV3) V3ScoreDirectComplete(bm gopay.BodyMap) (wxRsp *ScoreDirectCompleteRsp, err error) {
if bm.GetString("appid") == util.NULL {
bm.Set("appid", c.Appid)
}
authorization, err := c.authorization(MethodPost, v3ScoreDirectComplete, bm)
if err != nil {
return nil, err
}
res, si, bs, err := c.doProdPost(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("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)
}

// 商户预授权API
// Code = 0 is success
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_2.shtml
func (c *ClientV3) V3ScorePermission(bm gopay.BodyMap) (wxRsp *ScorePermissionRsp, err error) {
if bm.GetString("appid") == util.NULL {
bm.Set("appid", c.Appid)
}
authorization, err := c.authorization(MethodPost, v3ScorePermission, bm)
if err != nil {
return nil, err
}
res, si, bs, err := c.doProdPost(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("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)
}

// 查询用户授权记录(授权协议号)API
// Code = 0 is success
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_3.shtml
func (c *ClientV3) V3ScorePermissionQuery(authCode, serviceId string) (wxRsp *ScorePermissionQueryRsp, err error) {
url := fmt.Sprintf(v3ScorePermissionQuery, authCode)
uri := url + "?service_id=" + serviceId
authorization, err := c.authorization(MethodGet, uri, nil)
if err != nil {
return nil, err
}
res, si, bs, err := c.doProdGet(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("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)
}

// 解除用户授权关系(授权协议号)API
// Code = 0 is success
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_4.shtml
func (c *ClientV3) V3ScorePermissionTerminate(authCode, serviceId, reason string) (wxRsp *ScorePermissionTerminateRsp, 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(bm, url, authorization)
if err != nil {
return nil, err
}
wxRsp = &ScorePermissionTerminateRsp{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(openId, serviceId string) (wxRsp *ScorePermissionOpenidQueryRsp, err error) {
url := fmt.Sprintf(v3ScorePermissionOpenidQuery, openId)
uri := url + "?appid=" + c.Appid + "&service_id=" + serviceId
authorization, err := c.authorization(MethodGet, uri, nil)
if err != nil {
return nil, err
}
res, si, bs, err := c.doProdGet(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("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)
}

// 解除用户授权关系(openid)API
// Code = 0 is success
// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_6.shtml
func (c *ClientV3) V3ScorePermissionOpenidTerminate(openId, serviceId, reason string) (wxRsp *ScorePermissionOpenidTerminateRsp, err error) {
url := fmt.Sprintf(v3ScorePermissionOpenidTerminate, openId)
bm := make(gopay.BodyMap)
bm.Set("service_id", serviceId).
Set("appid", c.Appid).
Set("reason", reason)
authorization, err := c.authorization(MethodPost, url, bm)
if err != nil {
return nil, err
}
res, si, bs, err := c.doProdPost(bm, url, authorization)
if err != nil {
return nil, err
}
wxRsp = &ScorePermissionOpenidTerminateRsp{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
Expand Down Expand Up @@ -78,9 +240,9 @@ func (c *ClientV3) V3ScoreOrderQuery(orderNoType OrderNoType, orderNo, serviceId
func (c *ClientV3) V3ScoreOrderCancel(tradeNo, serviceId, reason string) (wxRsp *ScoreOrderCancelRsp, err error) {
url := fmt.Sprintf(v3ScoreOrderCancel, tradeNo)
bm := make(gopay.BodyMap)
bm.Set("appid", c.Appid)
bm.Set("service_id", serviceId)
bm.Set("reason", reason)
bm.Set("appid", c.Appid).
Set("service_id", serviceId).
Set("reason", reason)
authorization, err := c.authorization(MethodPost, url, bm)
if err != nil {
return nil, err
Expand Down Expand Up @@ -166,8 +328,8 @@ func (c *ClientV3) V3ScoreOrderComplete(tradeNo string, bm gopay.BodyMap) (wxRsp
func (c *ClientV3) V3ScoreOrderPay(tradeNo, serviceId string) (wxRsp *ScoreOrderPayRsp, err error) {
url := fmt.Sprintf(v3ScoreOrderPay, tradeNo)
bm := make(gopay.BodyMap)
bm.Set("appid", c.Appid)
bm.Set("service_id", serviceId)
bm.Set("appid", c.Appid).
Set("service_id", serviceId)
authorization, err := c.authorization(MethodPost, url, bm)
if err != nil {
return nil, err
Expand Down

0 comments on commit 2618339

Please sign in to comment.