commit 6f27df7342ad5836c6998bd2ed14facfb75bbe96 Author: 李光春 Date: Thu May 26 17:43:37 2022 +0800 - init diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..c56c479 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,17 @@ +kind: pipeline +type: docker +name: clone + +steps: + - name: Test + image: golang:1.18 + commands: + - go env -w GO111MODULE=on + - go env -w GOPROXY=https://goproxy.cn,direct + - go test -v ./... + - name: Benchmark + image: golang:1.18 + commands: + - go env -w GO111MODULE=on + - go env -w GOPROXY=https://goproxy.cn,direct + - go test -bench=. -benchmem \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..502d67a --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.env +.git +.svn +.idea +.vscode +*.log +goinit.sh +gomod.sh +/vendor/ +*_test.go \ No newline at end of file diff --git a/app.go b/app.go new file mode 100644 index 0000000..c753c47 --- /dev/null +++ b/app.go @@ -0,0 +1,73 @@ +package wechatunion + +import ( + "go.dtapp.net/golog" + "go.dtapp.net/goredis" + "go.dtapp.net/gorequest" + "gorm.io/gorm" +) + +const ( + UnionUrl = "https://api.weixin.qq.com/union" +) + +// App 微信小程序联盟 +type App struct { + appId string // 小程序唯一凭证,即 appId + appSecret string // 小程序唯一凭证密钥,即 appSecret + accessToken string // 接口调用凭证 + pid string // 推广位PID + Redis goredis.App // 缓存数据库服务 + pgsql *gorm.DB // pgsql数据库 + client *gorequest.App // 请求客户端 + log *golog.Api // 日志服务 + logTableName string // 日志表名 + logStatus bool // 日志状态 +} + +func NewApp(appId string, appSecret string, pid string, redis goredis.App, pgsql *gorm.DB) *App { + app := &App{appId: appId, appSecret: appSecret, pid: pid, Redis: redis} + app.client = gorequest.NewHttp() + if pgsql != nil { + app.pgsql = pgsql + app.logStatus = true + app.logTableName = "wechatunion" + app.log = golog.NewApi(&golog.ApiConfig{ + Db: pgsql, + TableName: app.logTableName, + }) + } + return app +} + +// 请求 +func (app *App) request(url string, params map[string]interface{}, method string) (resp gorequest.Response, err error) { + + // 创建请求 + client := app.client + + // 设置请求地址 + client.SetUri(url) + + // 设置请求方式 + client.SetMethod(method) + + // 设置FORM格式 + client.SetContentTypeForm() + + // 设置参数 + client.SetParams(params) + + // 发起请求 + request, err := client.Request() + if err != nil { + return gorequest.Response{}, err + } + + // 日志 + if app.logStatus == true { + go app.postgresqlLog(request) + } + + return request, err +} diff --git a/cgi-bin.token.monitor.go b/cgi-bin.token.monitor.go new file mode 100644 index 0000000..7a2c4a0 --- /dev/null +++ b/cgi-bin.token.monitor.go @@ -0,0 +1,20 @@ +package wechatunion + +import ( + "context" + "errors" + "time" +) + +func (app *App) GetAccessTokenMonitor() (string, error) { + if app.Redis.Db == nil { + return "", errors.New("驱动没有初始化") + } + result := app.GetCallBackIp() + if len(result.Result.IpList) <= 0 { + token := app.CgiBinToken() + app.Redis.Db.Set(context.Background(), app.getAccessTokenCacheKeyName(), token.Result.AccessToken, time.Second*7000) + return token.Result.AccessToken, nil + } + return app.accessToken, nil +} diff --git a/cgi-bin.token.rdb.go b/cgi-bin.token.rdb.go new file mode 100644 index 0000000..887232c --- /dev/null +++ b/cgi-bin.token.rdb.go @@ -0,0 +1,22 @@ +package wechatunion + +import ( + "fmt" + "time" +) + +func (app *App) GetAccessToken() string { + if app.Redis.Db == nil { + return app.accessToken + } + newCache := app.Redis.NewSimpleStringCache(app.Redis.NewStringOperation(), time.Second*7000) + newCache.DBGetter = func() string { + token := app.CgiBinToken() + return token.Result.AccessToken + } + return newCache.GetCache(app.getAccessTokenCacheKeyName()) +} + +func (app *App) getAccessTokenCacheKeyName() string { + return fmt.Sprintf("wechat_access_token:%v", app.appId) +} diff --git a/cgi_bin.token.go b/cgi_bin.token.go new file mode 100644 index 0000000..0ea0131 --- /dev/null +++ b/cgi_bin.token.go @@ -0,0 +1,38 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type CgiBinTokenResponse struct { + AccessToken string `json:"access_token"` // 获取到的凭证 + ExpiresIn int `json:"expires_in"` // 凭证有效时间,单位:秒。目前是7200秒之内的值 + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 +} + +type CgiBinTokenResult struct { + Result CgiBinTokenResponse // 结果 + Byte []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewCgiBinTokenResult(result CgiBinTokenResponse, byte []byte, http gorequest.Response, err error) *CgiBinTokenResult { + return &CgiBinTokenResult{Result: result, Byte: byte, Http: http, Err: err} +} + +// CgiBinToken +// 接口调用凭证 +// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html +func (app *App) CgiBinToken() *CgiBinTokenResult { + // 请求 + request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", app.appId, app.appSecret), map[string]interface{}{}, http.MethodGet) + // 定义 + var response CgiBinTokenResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewCgiBinTokenResult(response, request.ResponseBody, request, err) +} diff --git a/getcallbackip.go b/getcallbackip.go new file mode 100644 index 0000000..ecfee43 --- /dev/null +++ b/getcallbackip.go @@ -0,0 +1,35 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" +) + +type GetCallBackIpResponse struct { + IpList []string `json:"ip_list"` +} + +type GetCallBackIpResult struct { + Result GetCallBackIpResponse // 结果 + Byte []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewGetCallBackIpResult(result GetCallBackIpResponse, byte []byte, http gorequest.Response, err error) *GetCallBackIpResult { + return &GetCallBackIpResult{Result: result, Byte: byte, Http: http, Err: err} +} + +// GetCallBackIp 获取微信callback IP地址 +// callback IP即微信调用开发者服务器所使用的出口IP。 +// https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_the_WeChat_server_IP_address.html#2.%20%E8%8E%B7%E5%8F%96%E5%BE%AE%E4%BF%A1callback%20IP%E5%9C%B0%E5%9D%80 +func (app *App) GetCallBackIp() *GetCallBackIpResult { + app.accessToken = app.GetAccessToken() + // 请求 + request, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=%s", app.accessToken), map[string]interface{}{}, "GET") + // 定义 + var response GetCallBackIpResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewGetCallBackIpResult(response, request.ResponseBody, request, err) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f4b4348 --- /dev/null +++ b/go.mod @@ -0,0 +1,29 @@ +module go.dtapp.net/wechatunion + +go 1.18 + +require ( + go.dtapp.net/gojson v1.0.0 + go.dtapp.net/golog v1.0.13 + go.dtapp.net/goredis v1.0.0 + go.dtapp.net/gorequest v1.0.18 + go.dtapp.net/gotime v1.0.2 + gorm.io/datatypes v1.0.6 + gorm.io/gorm v1.23.5 +) + +require ( + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda // indirect + github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + go.dtapp.net/goip v1.0.16 // indirect + go.dtapp.net/gostring v1.0.3 // indirect + golang.org/x/text v0.3.7 // indirect + gorm.io/driver/mysql v1.3.3 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e0e81c2 --- /dev/null +++ b/go.sum @@ -0,0 +1,255 @@ +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA= +github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4= +github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.9.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.14.1/go.mod h1:RgDuE4Z34o7XE92RpLsvFiOEfrAUT0Xt2KxvX73W06M= +github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= +github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda h1:h+YpzUB/bGVJcLqW+d5GghcCmE/A25KbzjXvWJQi/+o= +github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda/go.mod h1:MSotTrCv1PwoR8QgU1JurEx+lNNbtr25I+m0zbLyAGw= +github.com/saracen/go7z-fixtures v0.0.0-20190623165746-aa6b8fba1d2f h1:PF9WV5j/x6MT+x/sauUHd4objCvJbZb0wdxZkHSdd5A= +github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f h1:1cJITU3JUI8qNS5T0BlXwANsVdyoJQHQ4hvOxbunPCw= +github.com/saracen/solidblock v0.0.0-20190426153529-45df20abab6f/go.mod h1:LyBTue+RWeyIfN3ZJ4wVxvDuvlGJtDgCLgCb6HCPgps= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.dtapp.net/goip v1.0.16 h1:jJoXeLVc8BmlKEc+4T9mL2BFK63RJFd4B9xTMYhFRqg= +go.dtapp.net/goip v1.0.16/go.mod h1:BY2Xo5clizPZFQ8CYOlgg91fHMZR1Ll54f3P0sNHxbg= +go.dtapp.net/gojson v1.0.0 h1:jmRjeWChRyv2tKEByHvnW3kXh1jUcL8B7VurV0Zbygc= +go.dtapp.net/gojson v1.0.0/go.mod h1:TkkpTNxHBKxul0e7gC5MrL1K4ICFB9mQ7wHzjBah3/k= +go.dtapp.net/golog v1.0.13 h1:SnU6G4onDYZPOfZ9cgmj5rHdtGGOWP/Qee31aM49Wj0= +go.dtapp.net/golog v1.0.13/go.mod h1:6w5Lt1x6/yUN3iptAi59irm4kqDJHaolDsrZ9ApsZUQ= +go.dtapp.net/goredis v1.0.0 h1:IvoOvdPeQlT2UR6lbumr+zN0x7ikTz9ro7od7jydD2U= +go.dtapp.net/goredis v1.0.0/go.mod h1:Wmrgb5yfbV7SiIK0NLdBOFWKnrQs+5g8p3t5+cjQkMM= +go.dtapp.net/gorequest v1.0.18 h1:NAogmkEbz4Sln4tt6Li8tF99d3WnHMkbPuYFdNz/xTE= +go.dtapp.net/gorequest v1.0.18/go.mod h1:EwOfdfxsWPszOWrphCWHTN4DbYtU6fyQ/fuWQyQwSnk= +go.dtapp.net/gostring v1.0.3 h1:KSOq4D77/g5yZN/bqWfZ0kOOaPr/P1240vg03+XdENI= +go.dtapp.net/gostring v1.0.3/go.mod h1:+ggrOvgQDQturi1QGsXEpyRN/ZPoRDaqhMujIk5lrgQ= +go.dtapp.net/gotime v1.0.2 h1:CFIJHQXC/4t9bsJhk2cLhjHd6rpdPcJXr8BcHKHDuQo= +go.dtapp.net/gotime v1.0.2/go.mod h1:Gq7eNLr2iMLP18UNWONRq4V3Uhf/ADp4bIrS+Tc6ktY= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898 h1:SLP7Q4Di66FONjDJbCYrCRrh97focO6sLogHO7/g8F0= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/datatypes v1.0.6 h1:3cqbakp1DIgC+P7wyODb5k+lSjW8g3mjkg/BIsmhjlE= +gorm.io/datatypes v1.0.6/go.mod h1:Gh/Xd/iUWWybMEk8CzYCK/swqlni2r+ROeM1HGIM0ck= +gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U= +gorm.io/driver/mysql v1.3.3 h1:jXG9ANrwBc4+bMvBcSl8zCfPBaVoPyBEBshA8dA93X8= +gorm.io/driver/mysql v1.3.3/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U= +gorm.io/driver/postgres v1.3.1/go.mod h1:WwvWOuR9unCLpGWCL6Y3JOeBWvbKi6JLhayiVclSZZU= +gorm.io/driver/postgres v1.3.6 h1:Q0iLoYvWwsJVpYQrSrY5p5P4YzW7fJjFMBG2sa4Bz5U= +gorm.io/driver/sqlite v1.3.1 h1:bwfE+zTEWklBYoEodIOIBwuWHpnx52Z9zJFW5F33WLk= +gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg= +gorm.io/driver/sqlserver v1.3.1 h1:F5t6ScMzOgy1zukRTIZgLZwKahgt3q1woAILVolKpOI= +gorm.io/driver/sqlserver v1.3.1/go.mod h1:w25Vrx2BG+CJNUu/xKbFhaKlGxT/nzRkhWCCoptX8tQ= +gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.2/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM= +gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/order.go b/order.go new file mode 100644 index 0000000..97c8a82 --- /dev/null +++ b/order.go @@ -0,0 +1,77 @@ +package wechatunion + +import ( + "errors" +) + +type OrderSearch struct { + Page int `json:"page,omitempty"` // 页码,起始为 1 + PageSize int `json:"pageSize,omitempty"` // 分页大小,最大 200 + StartTimestamp string `json:"startTimestamp,omitempty"` // 起始时间戳,单位为秒 + EndTimestamp string `json:"endTimestamp,omitempty"` // 结束时间戳,单位为秒 + CommissionStatus string `json:"commissionStatus,omitempty"` // 分佣状态 + SortByCommissionUpdateTime string `json:"sortByCommissionUpdateTime,omitempty"` // 是否按照分佣状态更新时间排序和筛选订单,1:是,0:否 + StartCommissionUpdateTime string `json:"startCommissionUpdateTime,omitempty"` // 分佣状态更新时间起始时间戳,单位为秒 + EndCommissionUpdateTime string `json:"endCommissionUpdateTime,omitempty"` // 分佣状态更新时间结束时间戳,单位为秒 +} + +type OrderSearchResult struct { + Errcode int `json:"errcode"` + Errmsg string `json:"errmsg"` + OrderList []struct { + OrderId string `json:"orderId"` // 订单ID + PayTime int `json:"payTime"` // 支付时间戳,单位为s + ConfirmReceiptTime int `json:"confirmReceiptTime"` // 确认收货时间戳,单位为s,没有时为0 + ShopName string `json:"shopName"` // 店铺名称 + ShopAppid string `json:"shopAppid"` // 店铺 Appid + ProductList []struct { + ProductId string `json:"productId"` // 商品SPU ID + SkuId string `json:"skuId"` // sku ID + Title string `json:"title"` // 商品名称 + ThumbImg string `json:"thumbImg"` // 商品缩略图 url + Price string `json:"price"` // 商品成交总价,前带单位 ¥ + ProductCnt int `json:"productCnt"` // 成交数量 + Ratio int `json:"ratio"` // 分佣比例,单位为万分之一 + CommissionStatus string `json:"commissionStatus"` // 分佣状态 + CommissionStatusUpdateTime string `json:"commissionStatusUpdateTime"` // 分佣状态更新时间戳,单位为s + ProfitShardingSucTime string `json:"profitShardingSucTime"` // 结算时间,当分佣状态为已结算才有值,单位为s + Commission string `json:"commission"` // 分佣金额,前带单位 ¥ + EstimatedCommission int `json:"estimatedCommission"` // 预估分佣金额,单位为分 + CategoryStr string `json:"categoryStr"` // 类目名称,多个用英文逗号分隔 + PromotionInfo struct { + PromotionSourcePid string `json:"promotionSourcePid"` // 推广位 id + PromotionSourceName string `json:"promotionSourceName"` // 推广位名称 + } `json:"promotionInfo"` // 推广信息 + CustomizeInfo string `json:"customizeInfo"` // 自定义信息 + } `json:"productList"` // 商品列表 + } `json:"orderList"` // 订单列表 + PageSize int `json:"pageSize"` // 分页大小 + TotalNum int `json:"totalNum"` // 订单总数 +} + +// OrderSearch 根据订单支付时间、订单分佣状态拉取订单详情 https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/order/order-info.html +func (app *App) OrderSearch(notMustParams ...Params) (result OrderSearchResult, err error) { + if len(app.accessToken) <= 0 { + return result, errors.New("调用凭证异常") + } + + // 参数 + //params := app.NewParamsWith(notMustParams...) + + //if len(orderIdList) <= 0 || len(orderIdList) > 200 { + // return result, errors.New("未传入 orderIdList 或 orderIdList 超过上限 200") + //} + + //body, err := app.request(fmt.Sprintf("https://api.weixin.qq.com/union/promoter/order/info?access_token=%s", app.accessToken), map[string]interface{}{ + // "orderIdList": orderIdList, + //}, http.MethodPost) + //if err != nil { + // return result, err + //} + //err = json.Unmarshal(body, &result) + //if err != nil { + // return result, err + //} + //return result, err + return +} diff --git a/params.go b/params.go new file mode 100644 index 0000000..52823e1 --- /dev/null +++ b/params.go @@ -0,0 +1,27 @@ +package wechatunion + +// Params 请求参数 +type Params map[string]interface{} + +func NewParams() Params { + p := make(Params) + return p +} + +func (app *App) NewParamsWith(params ...Params) Params { + p := make(Params) + for _, v := range params { + p.SetParams(v) + } + return p +} + +func (p Params) Set(key string, value interface{}) { + p[key] = value +} + +func (p Params) SetParams(params Params) { + for key, value := range params { + p[key] = value + } +} diff --git a/pgsql.go b/pgsql.go new file mode 100644 index 0000000..5c38991 --- /dev/null +++ b/pgsql.go @@ -0,0 +1,26 @@ +package wechatunion + +import ( + "go.dtapp.net/gojson" + "go.dtapp.net/golog" + "go.dtapp.net/gorequest" + "gorm.io/datatypes" +) + +// 记录日志 +func (app *App) postgresqlLog(request gorequest.Response) { + app.log.Record(golog.ApiPostgresqlLog{ + RequestTime: golog.TimeString{Time: request.RequestTime}, //【请求】时间 + RequestUri: request.RequestUri, //【请求】链接 + RequestUrl: gorequest.UriParse(request.RequestUri).Url, //【请求】链接 + RequestApi: gorequest.UriParse(request.RequestUri).Path, //【请求】接口 + RequestMethod: request.RequestMethod, //【请求】方式 + RequestParams: datatypes.JSON(gojson.JsonEncodeNoError(request.RequestParams)), //【请求】参数 + RequestHeader: datatypes.JSON(gojson.JsonEncodeNoError(request.RequestHeader)), //【返回】头部 + ResponseHeader: datatypes.JSON(gojson.JsonEncodeNoError(request.ResponseHeader)), //【返回】头部 + ResponseStatusCode: request.ResponseStatusCode, //【返回】状态码 + ResponseBody: request.ResponseBody, //【返回】内容 + ResponseContentLength: request.ResponseContentLength, //【返回】大小 + ResponseTime: golog.TimeString{Time: request.ResponseTime}, //【返回】时间 + }) +} diff --git a/promoter.order.info.go b/promoter.order.info.go new file mode 100644 index 0000000..0b1eb50 --- /dev/null +++ b/promoter.order.info.go @@ -0,0 +1,73 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromoterOrderInfoResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 + OrderList []struct { + OrderId string `json:"orderId"` // 订单ID + PayTime int64 `json:"payTime"` // 支付时间戳,单位为s + ConfirmReceiptTime int `json:"confirmReceiptTime"` // 确认收货时间戳,单位为s,没有时为0 + ShopName string `json:"shopName"` // 店铺名称 + ShopAppid string `json:"shopAppid"` // 店铺 Appid + ProductList []struct { + ProductId string `json:"productId"` // 商品SPU ID + SkuId string `json:"skuId"` // sku ID + Title string `json:"title"` // 商品名称 + ThumbImg string `json:"thumbImg"` // 商品缩略图 url + Price string `json:"price"` // 商品成交总价,前带单位 ¥ + ProductCnt int `json:"productCnt"` // 成交数量 + Ratio int64 `json:"ratio"` // 分佣比例,单位为万分之一 + CommissionStatus string `json:"commissionStatus"` // 分佣状态 + CommissionStatusUpdateTime string `json:"commissionStatusUpdateTime"` // 分佣状态更新时间戳,单位为s + ProfitShardingSucTime string `json:"profitShardingSucTime"` // 结算时间,当分佣状态为已结算才有值,单位为s + Commission string `json:"commission"` // 分佣金额,前带单位 ¥ + EstimatedCommission int `json:"estimatedCommission"` // 预估分佣金额,单位为分 + CategoryStr string `json:"categoryStr"` // 类目名称,多个用英文逗号分隔 + PromotionInfo struct { + PromotionSourcePid string `json:"promotionSourcePid"` // 推广位 id + PromotionSourceName string `json:"promotionSourceName"` // 推广位名称 + } `json:"promotionInfo"` // 推广信息 + CustomizeInfo string `json:"customizeInfo"` // 自定义信息 + } `json:"productList"` // 商品列表 + CustomUserId string `json:"customUserId"` // 自定义用户参数 + UserNickName string `json:"userNickName"` // 用户昵称 + OrderPrice string `json:"orderPrice"` // 支付金额,单位为分 + } `json:"orderList"` +} + +type PromoterOrderInfoResult struct { + Result PromoterOrderInfoResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromoterOrderInfoResult(result PromoterOrderInfoResponse, body []byte, http gorequest.Response, err error) *PromoterOrderInfoResult { + return &PromoterOrderInfoResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromoterOrderInfo 根据订单ID查询订单详情 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/order/order-info.html#_1-%E6%A0%B9%E6%8D%AE%E8%AE%A2%E5%8D%95ID%E6%9F%A5%E8%AF%A2%E8%AE%A2%E5%8D%95%E8%AF%A6%E6%83%85 +func (app *App) PromoterOrderInfo(orderId ...string) *PromoterOrderInfoResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := app.NewParamsWith() + var orderIdList []any + for _, v := range orderId { + orderIdList = append(orderIdList, v) + } + params.Set("orderIdList", orderIdList) + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/order/info?access_token=%s", app.accessToken), params, http.MethodPost) + // 定义 + var response PromoterOrderInfoResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromoterOrderInfoResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.order.search.go b/promoter.order.search.go new file mode 100644 index 0000000..b6ae169 --- /dev/null +++ b/promoter.order.search.go @@ -0,0 +1,70 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromoterOrderSearchResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 + OrderList []struct { + OrderId string `json:"orderId"` // 订单ID + PayTime int64 `json:"payTime"` // 支付时间戳,单位为s + ConfirmReceiptTime int `json:"confirmReceiptTime"` // 确认收货时间戳,单位为s,没有时为0 + ShopName string `json:"shopName"` // 店铺名称 + ShopAppid string `json:"shopAppid"` // 店铺 Appid + ProductList []struct { + ProductId string `json:"productId"` // 商品SPU ID + SkuId string `json:"skuId"` // sku ID + Title string `json:"title"` // 商品名称 + ThumbImg string `json:"thumbImg"` // 商品缩略图 url + Price string `json:"price"` // 商品成交总价,前带单位 ¥ + ProductCnt int `json:"productCnt"` // 成交数量 + Ratio int64 `json:"ratio"` // 分佣比例,单位为万分之一 + CommissionStatus string `json:"commissionStatus"` // 分佣状态 + CommissionStatusUpdateTime string `json:"commissionStatusUpdateTime"` // 分佣状态更新时间戳,单位为s + ProfitShardingSucTime string `json:"profitShardingSucTime"` // 结算时间,当分佣状态为已结算才有值,单位为s + Commission string `json:"commission"` // 分佣金额,前带单位 ¥ + EstimatedCommission int `json:"estimatedCommission"` // 预估分佣金额,单位为分 + CategoryStr string `json:"categoryStr"` // 类目名称,多个用英文逗号分隔 + PromotionInfo struct { + PromotionSourcePid string `json:"promotionSourcePid"` // 推广位 id + PromotionSourceName string `json:"promotionSourceName"` // 推广位名称 + } `json:"promotionInfo"` // 推广信息 + CustomizeInfo string `json:"customizeInfo"` // 自定义信息 + } `json:"productList"` // 商品列表 + CustomUserId string `json:"customUserId"` // 自定义用户参数 + UserNickName string `json:"userNickName"` // 用户昵称 + OrderPrice string `json:"orderPrice"` // 支付金额,单位为分 + } `json:"orderList"` // 订单列表 + PageSize int `json:"pageSize"` // 分页大小 + TotalNum int `json:"totalNum"` // 订单总数 +} + +type PromoterOrderSearchResult struct { + Result PromoterOrderSearchResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromoterOrderSearchResult(result PromoterOrderSearchResponse, body []byte, http gorequest.Response, err error) *PromoterOrderSearchResult { + return &PromoterOrderSearchResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromoterOrderSearch 根据订单支付时间、订单分佣状态拉取订单详情 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/order/order-info.html#_2-%E6%A0%B9%E6%8D%AE%E8%AE%A2%E5%8D%95%E6%94%AF%E4%BB%98%E6%97%B6%E9%97%B4%E3%80%81%E8%AE%A2%E5%8D%95%E5%88%86%E4%BD%A3%E7%8A%B6%E6%80%81%E6%8B%89%E5%8F%96%E8%AE%A2%E5%8D%95%E8%AF%A6%E6%83%85 +func (app *App) PromoterOrderSearch(notMustParams ...Params) *PromoterOrderSearchResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := app.NewParamsWith(notMustParams...) + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/order/search?access_token=%s", app.accessToken), params, http.MethodGet) + // 定义 + var response PromoterOrderSearchResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromoterOrderSearchResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.product.category.go b/promoter.product.category.go new file mode 100644 index 0000000..a95f998 --- /dev/null +++ b/promoter.product.category.go @@ -0,0 +1,40 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromoterProductCategoryResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 + ProductCats []struct { + CatId string `json:"catId"` // 类目ID + Name string `json:"name"` // 类目名称 + } `json:"productCats"` // 类目数据 +} + +type PromoterProductCategoryResult struct { + Result PromoterProductCategoryResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromoterProductCategoryResult(result PromoterProductCategoryResponse, body []byte, http gorequest.Response, err error) *PromoterProductCategoryResult { + return &PromoterProductCategoryResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromoterProductCategory 获取联盟商品类目列表及类目ID +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/product/category.html#_1-%E8%8E%B7%E5%8F%96%E8%81%94%E7%9B%9F%E5%95%86%E5%93%81%E7%B1%BB%E7%9B%AE%E5%88%97%E8%A1%A8%E5%8F%8A%E7%B1%BB%E7%9B%AEID +func (app *App) PromoterProductCategory() *PromoterProductCategoryResult { + app.accessToken = app.GetAccessToken() + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/product/category?access_token=%s", app.accessToken), map[string]interface{}{}, http.MethodGet) + // 定义 + var response PromoterProductCategoryResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromoterProductCategoryResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.product.generate.go b/promoter.product.generate.go new file mode 100644 index 0000000..41924f7 --- /dev/null +++ b/promoter.product.generate.go @@ -0,0 +1,69 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromoterProductGenerateResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 + List []struct { + ProductId string `json:"productId"` // 商品SPU ID + Pid string `json:"pid"` // 推广位PID + ProductInfo struct { + ProductId string `json:"productId"` // 商品SPU ID + Title string `json:"title"` // 商品标题 + SubTitle string `json:"subTitle"` // 商品子标题 + HeadImg []string `json:"headImg"` // 商品主图 + MinPrice int `json:"minPrice"` // 商品最低价格,单位分 + Discount int `json:"discount"` // 商品优惠金额,单位分 + DiscountPrice int `json:"discountPrice"` // 商品券后最低价格,单位分 + ShopName string `json:"shopName"` // 商店名称 + PluginResult int `json:"pluginResult"` // 是否引用小商店组件(未引用组件的商品不可推广),0:否,1:是 + TotalStockNum int `json:"totalStockNum"` // 商品库存 + } `json:"productInfo"` // 商品相关信息 + ShareInfo struct { + Username string `json:"username"` // 推广商品的小程序原始id + AppId string `json:"appId"` // 推广商品的小程序AppID + Path string `json:"path"` // 推广商品的小程序Path + CouponPath string `json:"couponPath"` // 推广商品的带券小程序Path + WxaCode string `json:"wxaCode"` // 已废弃。推广商品详情页的不带券葵花码图片 + CouponWxaCode string `json:"couponWxaCode"` // 已废弃。推广商品详情页的带券葵花码图片 + PromotionUrl string `json:"promotionUrl"` // 推广商品短链 + CouponPromotionUrl string `json:"couponPromotionUrl"` // 推广商品带券短链 + PromotionWording string `json:"promotionWording"` // 推广商品文案 + CouponPromotionWording string `json:"couponPromotionWording"` // 推广商品带券文案 + PromotionTag string `json:"promotionTag"` // 推广商品tag + CouponPromotionTag string `json:"couponPromotionTag"` // 推广商品带券tag + } `json:"shareInfo"` // 推广相关信息 + } `json:"list"` +} + +type PromoterProductGenerateResult struct { + Result PromoterProductGenerateResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromoterProductGenerateResult(result PromoterProductGenerateResponse, body []byte, http gorequest.Response, err error) *PromoterProductGenerateResult { + return &PromoterProductGenerateResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromoterProductGenerate 获取商品推广素材 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/product/category.html#_4-%E8%8E%B7%E5%8F%96%E5%95%86%E5%93%81%E6%8E%A8%E5%B9%BF%E7%B4%A0%E6%9D%90 +func (app *App) PromoterProductGenerate(notMustParams ...Params) *PromoterProductGenerateResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := app.NewParamsWith(notMustParams...) + params.Set("pid", app.pid) + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/product/generate?access_token=%s", app.accessToken), params, http.MethodPost) + // 定义 + var response PromoterProductGenerateResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromoterProductGenerateResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.product.list.go b/promoter.product.list.go new file mode 100644 index 0000000..6897800 --- /dev/null +++ b/promoter.product.list.go @@ -0,0 +1,152 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromoterProductListResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 + Msg string `json:"msg"` // 错误信息 + Total int `json:"total"` // 商品总数 + ProductList []struct { + ProductId string `json:"productId"` // 商品SPU ID + Product struct { + ProductId string `json:"productId"` // 商品SPU ID + Info struct { + Title string `json:"title"` // 商品标题 + SubTitle string `json:"subTitle"` // 商品子标题 + HeadImg []string `json:"headImg"` // 商品主图 + Category []struct { + CatId string `json:"catId"` // 类目ID + Name string `json:"name"` // 类目名称 + } `json:"category"` // 商品类目 + Brand string `json:"brand,omitempty"` // 品牌名称 + BrandId string `json:"brandId"` // 品牌ID + Model string `json:"model,omitempty"` // 型号 + Detail struct { + DetailImg []string `json:"detailImg"` // 商品详情图片 + } `json:"detail"` // 商品详细数据 + Param []interface{} `json:"param"` // 商品参数 + MinPrice int64 `json:"minPrice"` // 商品最低价格,单位分 + TotalStockNum int64 `json:"totalStockNum"` // 总库存 + TotalSoldNum int64 `json:"totalSoldNum"` // 累计销量 + TotalOrderNum int `json:"totalOrderNum"` // 累计订单量 + DiscountPrice int64 `json:"discountPrice"` // 商品券后价 + } `json:"info"` // 商品具体信息 + Skus []struct { + SkuId string `json:"skuId"` // 商品SKU ID + ProductSkuInfo struct { + ThumbImg string `json:"thumbImg"` // 商品SKU 小图 + SalePrice int `json:"salePrice"` // 商品SKU 销售价格,单位分 + MarketPrice int `json:"marketPrice"` // 商品SKU 市场价格,单位分 + StockInfo struct { + StockNum int `json:"stockNum"` // 商品SKU 库存 + } `json:"stockInfo"` + } `json:"productSkuInfo"` + } `json:"skus"` // 商品SKU + } `json:"product"` // 商品数据 + LeagueExInfo struct { + HasCommission int `json:"hasCommission"` // 是否有佣金,1/0 + CommissionRatio int64 `json:"commissionRatio"` // 佣金比例,万分之一 + CommissionValue int64 `json:"commissionValue"` // 佣金金额,单位分 + } `json:"leagueExInfo"` // 联盟佣金相关数据 + ShopInfo struct { + Name string `json:"name"` // 小商店名称 + AppId string `json:"appId"` // 小商店AppID + Username string `json:"username"` // 小商店原始id + HeadImgUrl string `json:"headImgUrl"` // 小商店店铺头像 + ShippingMethods struct { + Express int `json:"express"` // 是否支持快递,1:是,0:否 + SameCity int `json:"sameCity"` // 是否支持同城配送,1:是,0:否 + Pickup int `json:"pickup"` // 是否支持上门自提,1:是,0:否 + } `json:"shippingMethods"` // 配送方式 + AddressList []struct { + AddressInfo struct { + ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址 + CityName string `json:"cityName"` // 国标收货地址第二级地址 + CountyName string `json:"countyName"` // 国标收货地址第三级地址 + } `json:"addressInfo"` // 地址信息 + AddressType struct { + Express int `json:"express"` // 是否支持快递,1:是,0:否 + SameCity int `json:"sameCity"` // 是否支持同城配送,1:是,0:否 + Pickup int `json:"pickup"` // 是否支持上门自提,1:是,0:否 + } `json:"addressType"` // 地址类型 + } `json:"addressList"` // 发货地,只有当配送方式包含「同城配送、上门自提」才出该项 + SameCityTemplate struct { + DeliverScopeType int `json:"deliverScopeType"` // 配送范围的定义方式,0:按照距离定义配送范围,1:按照区域定义配送范围 + Scope string `json:"scope"` // 配送范围 + Region struct { + ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址 + CityName string `json:"cityName"` // 国标收货地址第二级地址 + CountyName string `json:"countyName"` // 国标收货地址第三级地址 + } `json:"region"` // 全城配送时的配送范围 + } `json:"sameCityTemplate"` // 配送范围,只有当配送方式包含「同城配送」才出该项 + FreightTemplate struct { + NotSendArea struct { + AddressInfoList []struct { + ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址 + CityName string `json:"cityName"` // 国标收货地址第二级地址 + CountyName string `json:"countyName"` // 国标收货地址第三级地址 + } `json:"addressInfoList"` // 不发货地区地址列表 + } `json:"notSendArea,omitempty"` // 不发货地区 + } `json:"freightTemplate"` // 运费模板,只有当配送方式包含「快递」才出此项 + } `json:"shopInfo"` // 商品所属小商店数据 + CouponInfo struct { + HasCoupon int `json:"hasCoupon"` // 是否有联盟券,1为含券商品,0为全部商品 + CouponId string `json:"couponId"` // 券id + CouponDetail struct { + RestNum int `json:"restNum"` // 券库存 + Type int `json:"type"` // 券类型 + DiscountInfo struct { + DiscountCondition struct { + ProductIds []string `json:"productIds"` // 指定商品 id + ProductCnt string `json:"productCnt"` // 商品数 + ProductPrice string `json:"productPrice"` // 商品金额 + } `json:"discountCondition"` // 指定商品 id + DiscountNum int `json:"discountNum,omitempty"` // 折扣数,如 5.1 折 为 5.1 * 1000 + DiscountFee string `json:"discountFee,omitempty"` // 直减金额,单位为分 + } `json:"discountInfo"` // 券面额 + ValidInfo struct { + ValidType int `json:"validType"` // 有效期类型,1 为商品指定时间区间,2 为生效天数 + ValidDayNum int `json:"validDayNum"` // 生效天数 + StartTime string `json:"startTime"` // 有效开始时间 + EndTime string `json:"endTime"` // 有效结束时间 + } `json:"validInfo"` // 有效期 + ReceiveInfo struct { + StartTime string `json:"startTime"` // 有效结束时间 + EndTime string `json:"endTime"` // 领取结束时间戳 + LimitNumOnePerson int `json:"limitNumOnePerson"` // 每人限领张数 + } `json:"receiveInfo"` // 领券时间 + } `json:"couponDetail"` // 券详情 + } `json:"couponInfo"` // 联盟优惠券数据 + } `json:"productList"` // 商品列表数据 +} + +type PromoterProductListResult struct { + Result PromoterProductListResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromoterProductListResult(result PromoterProductListResponse, body []byte, http gorequest.Response, err error) *PromoterProductListResult { + return &PromoterProductListResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromoterProductList 查询全量商品 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/product/category.html#_2-%E6%9F%A5%E8%AF%A2%E5%85%A8%E9%87%8F%E5%95%86%E5%93%81 +func (app *App) PromoterProductList(notMustParams ...Params) *PromoterProductListResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := app.NewParamsWith(notMustParams...) + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/product/list?access_token=%s", app.accessToken), params, http.MethodGet) + // 定义 + var response PromoterProductListResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromoterProductListResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.product.select.go b/promoter.product.select.go new file mode 100644 index 0000000..c9189aa --- /dev/null +++ b/promoter.product.select.go @@ -0,0 +1,153 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromoterProductSelectResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 + Total int64 `json:"total"` // 商品总数 + ProductList []struct { + ProductId string `json:"productId"` // 商品SPU ID + Product struct { + ProductId string `json:"productId"` // 商品SPU ID + Info struct { + Title string `json:"title"` // 商品标题 + SubTitle string `json:"subTitle"` // 商品子标题 + HeadImg []string `json:"headImg"` // 商品主图 + Category []struct { + CatId string `json:"catId"` // 类目ID + Name string `json:"name"` // 类目ID + } `json:"category"` // 商品类目 + Brand string `json:"brand"` // 品牌名称 + BrandId string `json:"brandId"` // 品牌ID + Model string `json:"model"` // 型号 + Detail struct { + DetailImg []string `json:"detailImg"` // 商品详情图片 + } `json:"detail"` // 商品详细数据 + Param []interface{} `json:"param"` // 商品参数 + MinPrice int64 `json:"minPrice"` // 商品最低价格,单位分 + TotalStockNum int64 `json:"totalStockNum"` // 总库存 + TotalSoldNum int `json:"totalSoldNum"` // 累计销量 + TotalOrderNum int `json:"totalOrderNum"` // 累计订单量 + DiscountPrice int64 `json:"discountPrice"` // 商品券后价 + } `json:"info"` // 商品具体信息 + Skus []struct { + SkuId string `json:"skuId"` // 商品SKU ID + ProductSkuInfo struct { + ThumbImg string `json:"thumbImg"` // 商品SKU 小图 + SalePrice int `json:"salePrice"` // 商品SKU 销售价格,单位分 + MarketPrice int `json:"marketPrice,omitempty"` // 商品SKU 市场价格,单位分 + StockInfo struct { + StockNum int `json:"stockNum"` // 商品SKU 库存 + } `json:"stockInfo"` + } `json:"productSkuInfo"` + } `json:"skus"` // 商品SKU + } `json:"product"` // 商品数据 + LeagueExInfo struct { + HasCommission int `json:"hasCommission"` // 是否有佣金,1/0 + CommissionRatio int64 `json:"commissionRatio"` // 佣金比例,万分之一 + CommissionValue int64 `json:"commissionValue"` // 佣金金额,单位分 + } `json:"leagueExInfo"` // 联盟佣金相关数据 + ShopInfo struct { + Name string `json:"name"` // 小商店名称 + AppId string `json:"appId"` // 小商店AppID + Username string `json:"username"` // 小商店原始id + HeadImgUrl string `json:"headImgUrl"` // 小商店店铺头像 + AddressList []struct { + AddressInfo struct { + ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址 + CityName string `json:"cityName"` // 国标收货地址第二级地址 + CountyName string `json:"countyName"` // 国标收货地址第三级地址 + } `json:"addressInfo"` // 地址信息 + AddressType struct { + Express int `json:"express"` // 是否支持快递,1:是,0:否 + SameCity int `json:"sameCity"` // 是否支持同城配送,1:是,0:否 + Pickup int `json:"pickup"` // 是否支持上门自提,1:是,0:否 + } `json:"addressType"` // 地址类型 + } `json:"addressList"` // 发货地,只有当配送方式包含「同城配送、上门自提」才出该项 + ShippingMethods struct { + Express int `json:"express"` // 是否支持快递,1:是,0:否 + SameCity int `json:"sameCity"` // 是否支持同城配送,1:是,0:否 + Pickup int `json:"pickup"` // 是否支持上门自提,1:是,0:否 + } `json:"shippingMethods"` // 配送方式 + SameCityTemplate struct { + DeliverScopeType int `json:"deliverScopeType"` // 配送范围的定义方式,0:按照距离定义配送范围,1:按照区域定义配送范围 + Scope string `json:"scope"` // 配送范围 + Region struct { + ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址 + CityName string `json:"cityName"` // 国标收货地址第二级地址 + CountyName string `json:"countyName"` // 国标收货地址第三级地址 + } `json:"region"` // 全城配送时的配送范围 + } `json:"sameCityTemplate"` // 配送范围,只有当配送方式包含「同城配送」才出该项 + FreightTemplate struct { + NotSendArea struct { + AddressInfoList []struct { + ProvinceName string `json:"provinceName"` // 国标收货地址第一级地址 + CityName string `json:"cityName"` // 国标收货地址第二级地址 + CountyName string `json:"countyName"` // 国标收货地址第三级地址 + } `json:"addressInfoList"` // 不发货地区地址列表 + } `json:"notSendArea,omitempty"` // 不发货地区 + } `json:"freightTemplate"` // 运费模板,只有当配送方式包含「快递」才出此项 + } `json:"shopInfo"` // 商品所属小商店数据 + CouponInfo struct { + HasCoupon int `json:"hasCoupon"` // 是否有联盟券,1为含券商品,0为全部商品 + CouponId string `json:"couponId"` // 券id + CouponDetail struct { + RestNum int `json:"restNum"` // 券库存 + Type int `json:"type"` // 券类型 + DiscountInfo struct { + DiscountCondition struct { + ProductIds []string `json:"productIds"` // 指定商品 id + ProductCnt string `json:"productCnt"` // 商品数 + ProductPrice string `json:"productPrice"` // 商品金额 + } `json:"discountCondition"` // 指定商品 id + DiscountNum int `json:"discountNum,omitempty"` // 折扣数,如 5.1 折 为 5.1 * 1000 + DiscountFee int64 `json:"discountFee,omitempty"` // 直减金额,单位为分 + } `json:"discountInfo"` // 券面额 + ValidInfo struct { + ValidType int `json:"validType"` // 有效期类型,1 为商品指定时间区间,2 为生效天数 + ValidDayNum int `json:"validDayNum"` // 生效天数 + StartTime string `json:"startTime"` // 有效开始时间 + EndTime string `json:"endTime"` // 有效结束时间 + } `json:"validInfo"` // 有效期 + ReceiveInfo struct { + StartTime string `json:"startTime"` // 有效结束时间 + EndTime string `json:"endTime"` // 领取结束时间戳 + LimitNumOnePerson int `json:"limitNumOnePerson"` // 每人限领张数 + } `json:"receiveInfo"` // 领券时间 + } `json:"couponDetail"` // 券详情 + } `json:"couponInfo"` // 联盟优惠券数据 + } `json:"productList"` // 商品列表数据 +} + +type PromoterProductSelectResult struct { + Result PromoterProductSelectResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromoterProductSelectResult(result PromoterProductSelectResponse, body []byte, http gorequest.Response, err error) *PromoterProductSelectResult { + return &PromoterProductSelectResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromoterProductSelect +// 查询联盟精选商品 +// 支持开发者根据多种筛选条件获取联盟精选的商品列表及详情,筛选条件包括商品价格、商品佣金、商品累计销量、佣金比例、是否含有联盟券、配送方式、发货地区 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/product/category.html#3.%E6%9F%A5%E8%AF%A2%E8%81%94%E7%9B%9F%E7%B2%BE%E9%80%89%E5%95%86%E5%93%81 +func (app *App) PromoterProductSelect(notMustParams ...Params) *PromoterProductSelectResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := app.NewParamsWith(notMustParams...) + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/product/select?access_token=%s", app.accessToken), params, http.MethodGet) + // 定义 + var response PromoterProductSelectResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromoterProductSelectResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.promotion.add.go b/promoter.promotion.add.go new file mode 100644 index 0000000..3e703c9 --- /dev/null +++ b/promoter.promotion.add.go @@ -0,0 +1,40 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromotionAddResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 + Pid string `json:"pid"` // 推广位ID,PID +} + +type PromotionAddResult struct { + Result PromotionAddResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromotionAddResult(result PromotionAddResponse, body []byte, http gorequest.Response, err error) *PromotionAddResult { + return &PromotionAddResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromotionAdd 添加推广位 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/promotion.html#_1-%E6%B7%BB%E5%8A%A0%E6%8E%A8%E5%B9%BF%E4%BD%8D +func (app *App) PromotionAdd(promotionSourceName string) *PromotionAddResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := NewParams() + params.Set("promotionSourceName", promotionSourceName) // 推广位名称 + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/promotion/add?access_token%s", app.accessToken), params, http.MethodPost) + // 定义 + var response PromotionAddResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromotionAddResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.promotion.del.go b/promoter.promotion.del.go new file mode 100644 index 0000000..02cccf2 --- /dev/null +++ b/promoter.promotion.del.go @@ -0,0 +1,40 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromotionDelResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 +} + +type PromotionDelResult struct { + Result PromotionDelResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromotionDelResult(result PromotionDelResponse, body []byte, http gorequest.Response, err error) *PromotionDelResult { + return &PromotionDelResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromotionDel 删除某个推广位 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/promotion.html#_3-%E7%BC%96%E8%BE%91%E6%8E%A8%E5%B9%BF%E4%BD%8D +func (app *App) PromotionDel(promotionSourcePid, promotionSourceName string) *PromotionDelResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := NewParams() + params.Set("promotionSourcePid", promotionSourcePid) // 推广位PID + params.Set("promotionSourceName", promotionSourceName) // 推广位名称 + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/promotion/del?access_token%s", app.accessToken), params, http.MethodPost) + // 定义 + var response PromotionDelResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromotionDelResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.promotion.list.go b/promoter.promotion.list.go new file mode 100644 index 0000000..36993e3 --- /dev/null +++ b/promoter.promotion.list.go @@ -0,0 +1,48 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromotionListResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 + PromotionSourceList []struct { + PromotionSourceName string `json:"promotionSourceName"` // 推广位名称 + PromotionSourcePid string `json:"promotionSourcePid"` // 推广位ID,PID + Status string `json:"status"` // 状态 + PidId string `json:"pidId"` + } `json:"promotionSourceList"` // 推广位数据 + Total int `json:"total"` // 推广位总数 + PromotionMaxCnt int `json:"promotionMaxCnt"` // 允许创建的推广位最大数量 +} + +type PromotionListResult struct { + Result PromotionListResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromotionListResult(result PromotionListResponse, body []byte, http gorequest.Response, err error) *PromotionListResult { + return &PromotionListResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromotionList 获取推广位列表 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/promotion.html#_4-%E8%8E%B7%E5%8F%96%E6%8E%A8%E5%B9%BF%E4%BD%8D%E5%88%97%E8%A1%A8 +func (app *App) PromotionList(start int, limit int) *PromotionListResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := NewParams() + params.Set("start", start) // 偏移 + params.Set("limit", limit) // 每页条数 + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/promotion/list?access_token%s", app.accessToken), params, http.MethodGet) + // 定义 + var response PromotionListResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromotionListResult(response, request.ResponseBody, request, err) +} diff --git a/promoter.promotion.upd.go b/promoter.promotion.upd.go new file mode 100644 index 0000000..0756183 --- /dev/null +++ b/promoter.promotion.upd.go @@ -0,0 +1,38 @@ +package wechatunion + +import ( + "encoding/json" + "fmt" + "go.dtapp.net/gorequest" + "net/http" +) + +type PromotionUpdResponse struct { + Errcode int `json:"errcode"` // 错误码 + Errmsg string `json:"errmsg"` // 错误信息 +} + +type PromotionUpdResult struct { + Result PromotionUpdResponse // 结果 + Body []byte // 内容 + Http gorequest.Response // 请求 + Err error // 错误 +} + +func NewPromotionUpdResult(result PromotionUpdResponse, body []byte, http gorequest.Response, err error) *PromotionUpdResult { + return &PromotionUpdResult{Result: result, Body: body, Http: http, Err: err} +} + +// PromotionUpd 编辑推广位 +// https://developers.weixin.qq.com/doc/ministore/union/access-guidelines/promoter/api/promotion.html#_3-%E7%BC%96%E8%BE%91%E6%8E%A8%E5%B9%BF%E4%BD%8D +func (app *App) PromotionUpd(notMustParams ...Params) *PromotionUpdResult { + app.accessToken = app.GetAccessToken() + // 参数 + params := app.NewParamsWith(notMustParams...) + // 请求 + request, err := app.request(UnionUrl+fmt.Sprintf("/promoter/promotion/upd?access_token%s", app.accessToken), params, http.MethodPost) + // 定义 + var response PromotionUpdResponse + err = json.Unmarshal(request.ResponseBody, &response) + return NewPromotionUpdResult(response, request.ResponseBody, request, err) +} diff --git a/version.go b/version.go new file mode 100644 index 0000000..4e1925f --- /dev/null +++ b/version.go @@ -0,0 +1,3 @@ +package wechatunion + +const Version = "1.0.0"