滴滴联盟的api,添加支付宝小程序链接

This commit is contained in:
wukesheng 2024-05-15 22:01:40 +08:00
parent ac4dff4713
commit 4a40f28e7a
8 changed files with 241 additions and 28 deletions

8
go.mod
View File

@ -3,12 +3,12 @@ module gitee.com/chengdu-lenntc/third-platform-sdk
go 1.19
require (
github.com/BurntSushi/toml v1.0.0 // indirect
github.com/google/uuid v1.3.0
github.com/stretchr/testify v1.8.4
github.com/zeromicro/go-zero v1.5.5
github.com/zywaited/xcopy v1.1.0
github.com/BurntSushi/toml v1.0.0 // indirect
github.com/google/uuid v1.3.0
go.uber.org/zap v1.21.0
go.uber.org/zap v1.24.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)
@ -22,7 +22,9 @@ require (
github.com/spaolacci/murmur3 v1.1.0 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/sys v0.11.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -2,34 +2,40 @@ package didi_union
import (
"context"
"errors"
"fmt"
"time"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zywaited/xcopy"
"gitee.com/chengdu-lenntc/third-platform-sdk/sdk/dunion-go-sdk/model"
sdkutil "gitee.com/chengdu-lenntc/third-platform-sdk/sdk/dunion-go-sdk/util"
)
// todo:: 定义统一的返回错误结构
// DidiUnionApi 调用第三方平台的api
// Api defines the interface of eleme_union api
type DidiUnionApi interface {
// Sign 签名
Sign(data map[string]interface{}) string
// GenerateH5Link 生成h5推广链接
GenerateH5Link(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*model.LinkResponse, error)
GenerateH5Link(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*GenerateLinkResponse, error)
// GenerateMiniLink 生成小程序页面推广路径
GenerateMiniLink(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*model.LinkResponse, error)
GenerateMiniLink(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*GenerateLinkResponse, error)
// GenerateAlipayMiniLink 生成支付宝小程序页面推广路径
GenerateAlipayMiniLink(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*GenerateLinkResponse, error)
// GenerateH5Code 生成h5二维码需先取链得到dsi
GenerateH5Code(ctx context.Context, req GenerateCodeRequest, opt model.Option) (*model.QrcodeResponse, error)
GenerateH5Code(ctx context.Context, req GenerateCodeRequest, opt model.Option) (*GenerateCodeResponse, error)
// GenerateMiniCode 生成小程序太阳码需先取链得到dsi
GenerateMiniCode(ctx context.Context, req GenerateCodeRequest, opt model.Option) (*model.QrcodeResponse, error)
GenerateMiniCode(ctx context.Context, req GenerateCodeRequest, opt model.Option) (*GenerateCodeResponse, error)
// GeneratePoster 生成推广海报需先取链得到dsi
GeneratePoster(ctx context.Context, req GeneratePosterRequest, opt model.Option) (*model.PosterResponse, error)
GeneratePoster(ctx context.Context, req GeneratePosterRequest, opt model.Option) (*GeneratePosterResponse, error)
// QueryOrderList 查询订单列表
QueryOrderList(ctx context.Context, req QueryOrderListRequest, opt model.Option) (*model.OrderResponse, error)
QueryOrderList(ctx context.Context, req QueryOrderListRequest, opt model.Option) (*QueryOrderListResponse, error)
// SelfQueryOrder 订单归因问题自查询
SelfQueryOrder(ctx context.Context, req SelfQueryOrderRequest, opt model.Option) (*model.SelfQueryResponse, error)
SelfQueryOrder(ctx context.Context, req SelfQueryOrderRequest, opt model.Option) (*SelfQueryOrderResponse, error)
}
type didiUnionApiImpl struct {
@ -53,36 +59,153 @@ func (d *didiUnionApiImpl) Sign(params map[string]any) string {
}
// GenerateH5Link 生成h5推广链接
func (d *didiUnionApiImpl) GenerateH5Link(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*model.LinkResponse, error) {
return d.client.clt.GenerateH5Link(ctx, req.ActivityID, req.PromotionID, req.SourceID, opt)
func (d *didiUnionApiImpl) GenerateH5Link(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*GenerateLinkResponse, error) {
resp, err := d.client.clt.GenerateH5Link(ctx, req.ActivityID, req.PromotionID, req.SourceID, opt)
if err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateH5Link] get link http request error, error: %v", err)
return nil, err
}
if resp.Errno > 0 {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateH5Link] get link error, error: %v", resp.ErrorMsg())
return nil, errors.New(resp.ErrMsg)
}
var result *GenerateLinkResponse
if err := xcopy.Copy(&result, resp.Data); err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateH5Link] copy resp to result error, error: %v", err)
return nil, errors.New(resp.ErrMsg)
}
return result, nil
}
// GenerateMiniLink 生成小程序页面推广路径
func (d *didiUnionApiImpl) GenerateMiniLink(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*model.LinkResponse, error) {
return d.client.clt.GenerateMiniLink(ctx, req.ActivityID, req.PromotionID, req.SourceID, opt)
func (d *didiUnionApiImpl) GenerateMiniLink(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*GenerateLinkResponse, error) {
resp, err := d.client.clt.GenerateMiniLink(ctx, req.ActivityID, req.PromotionID, req.SourceID, opt)
if err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateMiniLink] http request error, error: %v", err)
return nil, err
}
if resp.Errno > 0 {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateMiniLink] get link error, error: %v", resp.ErrorMsg())
return nil, errors.New(resp.ErrMsg)
}
var result *GenerateLinkResponse
if err := xcopy.Copy(&result, resp.Data); err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateMiniLink] copy resp to result error, error: %v", err)
return nil, errors.New(resp.ErrMsg)
}
return result, nil
}
// GenerateAlipayMiniLink 生成小程序页面推广路径
func (d *didiUnionApiImpl) GenerateAlipayMiniLink(ctx context.Context, req GenerateLinkRequest, opt model.Option) (*GenerateLinkResponse, error) {
resp, err := d.client.clt.GenerateAlipayMiniLink(ctx, req.ActivityID, req.PromotionID, req.SourceID, opt)
if err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateAlipayMiniLink] http request error, error: %v", err)
return nil, err
}
if resp.Errno > 0 {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateAlipayMiniLink] get link error, error: %v", resp.ErrorMsg())
return nil, errors.New(resp.ErrMsg)
}
var result *GenerateLinkResponse
if err := xcopy.Copy(&result, resp.Data); err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateAlipayMiniLink] copy resp to result error, error: %v", err)
return nil, errors.New(resp.ErrMsg)
}
return result, nil
}
// GenerateH5Code 生成h5二维码需先取链得到dsi
func (d *didiUnionApiImpl) GenerateH5Code(ctx context.Context, req GenerateCodeRequest, opt model.Option) (*model.QrcodeResponse, error) {
return d.client.clt.GenerateH5Code(ctx, req.Dsi, req.SourceID, opt)
func (d *didiUnionApiImpl) GenerateH5Code(ctx context.Context, req GenerateCodeRequest, opt model.Option) (*GenerateCodeResponse, error) {
resp, err := d.client.clt.GenerateH5Code(ctx, req.Dsi, req.SourceID, opt)
if err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateH5Code] http request error, error: %v", err)
return nil, err
}
if resp.Errno > 0 {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateH5Code] get h5 code error, error: %v", resp.ErrorMsg())
return nil, errors.New(resp.ErrMsg)
}
var result *GenerateCodeResponse
if err := xcopy.Copy(&result, resp.Data); err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateH5Code] copy resp to result error, error: %v", err)
return nil, errors.New(resp.ErrMsg)
}
return result, nil
}
// GenerateMiniCode 生成小程序太阳码需先取链得到dsi
func (d *didiUnionApiImpl) GenerateMiniCode(ctx context.Context, req GenerateCodeRequest, opt model.Option) (*model.QrcodeResponse, error) {
return d.client.clt.GenerateMiniCode(ctx, req.Dsi, req.SourceID, opt)
func (d *didiUnionApiImpl) GenerateMiniCode(ctx context.Context, req GenerateCodeRequest, opt model.Option) (*GenerateCodeResponse, error) {
resp, err := d.client.clt.GenerateMiniCode(ctx, req.Dsi, req.SourceID, opt)
if err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateMiniCode] http request error, error: %v", err)
return nil, err
}
if resp.Errno > 0 {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateMiniCode] get mini code error, error: %v", resp.ErrorMsg())
return nil, errors.New(resp.ErrMsg)
}
var result *GenerateCodeResponse
if err := xcopy.Copy(&result, resp.Data); err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GenerateMiniCode] copy resp to result error, error: %v", err)
return nil, errors.New(resp.ErrMsg)
}
return result, nil
}
// GeneratePoster 生成推广海报需先取链得到dsi
func (d *didiUnionApiImpl) GeneratePoster(ctx context.Context, req GeneratePosterRequest, opt model.Option) (*model.PosterResponse, error) {
return d.client.clt.GeneratePoster(ctx, req.Dsi, req.SourceID, opt)
func (d *didiUnionApiImpl) GeneratePoster(ctx context.Context, req GeneratePosterRequest, opt model.Option) (*GeneratePosterResponse, error) {
resp, err := d.client.clt.GeneratePoster(ctx, req.Dsi, req.SourceID, opt)
if err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GeneratePoster] http request error, error: %v", err)
return nil, err
}
if resp.Errno > 0 {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GeneratePoster] generate poster error, error: %v", resp.ErrorMsg())
return nil, errors.New(resp.ErrMsg)
}
var result *GeneratePosterResponse
if err := xcopy.Copy(&result, resp.Data); err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][GeneratePoster] copy resp to result error, error: %v", err)
return nil, errors.New(resp.ErrMsg)
}
return result, nil
}
// QueryOrderList 查询订单列表
func (d *didiUnionApiImpl) QueryOrderList(ctx context.Context, req QueryOrderListRequest, opt model.Option) (*model.OrderResponse, error) {
return d.client.clt.QueryOrderList(ctx, req.StartTime, req.EndTime, string(req.Typ), req.Page, req.Size, opt)
func (d *didiUnionApiImpl) QueryOrderList(ctx context.Context, req QueryOrderListRequest, opt model.Option) (*QueryOrderListResponse, error) {
resp, err := d.client.clt.QueryOrderList(ctx, req.StartTime, req.EndTime, string(req.Typ), req.Page, req.Size, opt)
if err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][QueryOrderList] http request error, error: %v", err)
return nil, err
}
if resp.Errno > 0 {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][QueryOrderList] get order list error, error: %v", resp.ErrorMsg())
return nil, errors.New(resp.ErrMsg)
}
var result *QueryOrderListResponse
if err := xcopy.Copy(&result, resp.Data); err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][QueryOrderList] copy resp to result error, error: %v", err)
return nil, errors.New(resp.ErrMsg)
}
return result, nil
}
// SelfQueryOrder 订单归因问题自查询
func (d *didiUnionApiImpl) SelfQueryOrder(ctx context.Context, req SelfQueryOrderRequest, opt model.Option) (*model.SelfQueryResponse, error) {
return d.client.clt.SelfQueryOrder(ctx, req.OrderID, opt)
func (d *didiUnionApiImpl) SelfQueryOrder(ctx context.Context, req SelfQueryOrderRequest, opt model.Option) (*SelfQueryOrderResponse, error) {
resp, err := d.client.clt.SelfQueryOrder(ctx, req.OrderID, opt)
if err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][SelfQueryOrder] http request error, error: %v", err)
return nil, err
}
if resp.Errno > 0 {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][SelfQueryOrder] query self order error, error: %v", resp.ErrorMsg())
return nil, errors.New(resp.ErrMsg)
}
var result *SelfQueryOrderResponse
if err := xcopy.Copy(&result, resp.Data); err != nil {
d.log.WithFields(logx.LogField{Key: "req", Value: req}).Errorf("[didiUnionApiImpl][SelfQueryOrder] copy resp to result error, error: %v", err)
return nil, errors.New(resp.ErrMsg)
}
return result, nil
}

View File

@ -3,9 +3,12 @@ package didi_union
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/suite"
"github.com/zeromicro/go-zero/core/logx"
"gitee.com/chengdu-lenntc/third-platform-sdk/sdk/dunion-go-sdk/model"
)
// api-单元测试
@ -35,3 +38,20 @@ func (a *apiClientSuite) Test_Sign() {
sign := a.api.Sign(data)
a.T().Logf("=====[TestSign] sign: %s", sign)
}
func (a *apiClientSuite) Test_GenerateH5Link() {
ctx := context.Background()
req := GenerateLinkRequest{
ActivityID: 207811824611,
PromotionID: 7193964476899539205,
SourceID: "test",
}
opt := model.Option{
Timeout: time.Second * 10,
}
resp, err := a.api.GenerateH5Link(ctx, req, opt)
if !a.NoError(err) {
a.T().Errorf("=====[TestGenerateH5Link] err: %v", err)
}
a.T().Logf("=====[TestGenerateH5Link] resp: %+v, err: %v", resp, err)
}

View File

@ -1,6 +1,10 @@
package didi_union
import "time"
import (
"time"
"gitee.com/chengdu-lenntc/third-platform-sdk/sdk/dunion-go-sdk/model"
)
// GenerateLinkRequest 生成推广链接的请求
type GenerateLinkRequest struct {
@ -9,8 +13,17 @@ type GenerateLinkRequest struct {
SourceID string // 来源id (用于标明订单来源)
}
// 生成推广链接的响应
// GenerateLinkResponse 生成推广链接的响应
type GenerateLinkResponse struct {
//生成的链接
//example: https://v.didi.cn/p/abcd
Link string `json:"link"`
//实例ID可通过此ID去生成海报或者二维码
DSI string `json:"dsi"`
//小程序appid
AppId string `json:"app_id,omitempty"`
//小程序原始ID
AppSource string `json:"app_source,omitempty"`
}
// GenerateCodeRequest 生成二维码的请求
@ -19,12 +32,26 @@ type GenerateCodeRequest struct {
SourceID string // 来源id (用于标明订单来源)
}
// GenerateCodeResponse 生成二维码的响应
type GenerateCodeResponse struct {
//生成的二维码链接
//example: https://example.com/img.jpg
CodeLink string `json:"code_link"`
}
// GeneratePosterRequest 生成海报的请求
type GeneratePosterRequest struct {
Dsi string // 活动ID+推广位ID决定一个DSI (需先取链得到dsi)
SourceID string // 来源id (用于标明订单来源)
}
// GeneratePosterResponse 生成海报的响应
type GeneratePosterResponse struct {
//生成的海报链接
//example: https://example.com/img.jpg
PosterLink string `json:"poster_link"`
}
// QueryOrderListRequest 订单列表请求
type QueryOrderListRequest struct {
StartTime time.Time // 开始时间
@ -34,7 +61,23 @@ type QueryOrderListRequest struct {
Size int // 每页数量最大值为100
}
// QueryOrderListResponse 订单列表响应
type QueryOrderListResponse struct {
// 总数量
// example: 1
Total int `json:"total"`
OrderList []*model.ResponseOrderItem `json:"order_list"`
}
// SelfQueryOrderRequest 自查询订单请求
type SelfQueryOrderRequest struct {
OrderID string // 订单ID
}
// SelfQueryOrderResponse 订单归因问题自查询响应
type SelfQueryOrderResponse struct {
// 推广成功列表
EstimateSuccessList []*model.EstimateSuccessData `json:"estimate_success_list,omitempty" structs:"estimate_success_list"`
// 推广失败列表
EstimateFailList []*model.EstimateFailData `json:"estimate_fail_list,omitempty" structs:"estimate_fail_list"`
}

View File

@ -2,6 +2,7 @@ package eleme_union
import (
"context"
"encoding/json"
"testing"
"time"
@ -80,5 +81,10 @@ func (a *apiClientSuite) Test_KbcpxPositiveOrderGet() {
a.T().Errorf("=====[Test_GetOrders] err: %v", err)
return
}
a.T().Logf("=====[Test_GetOrders] resp: %+v", resp)
respStr, err := json.Marshal(resp)
if err != nil {
a.T().Errorf("=====[Test_GetOrders] err: %v", err)
return
}
a.T().Logf("=====[Test_GetOrders] resp: %+v", string(respStr))
}

View File

@ -19,6 +19,7 @@ type client struct {
type UnionClient interface {
GenerateH5Link(ctx context.Context, activityID, promotionID int64, sourceID string, opt ...model.Option) (*model.LinkResponse, error)
GenerateMiniLink(ctx context.Context, activityID, promotionID int64, sourceID string, opt ...model.Option) (*model.LinkResponse, error)
GenerateAlipayMiniLink(ctx context.Context, activityID, promotionID int64, sourceID string, opt ...model.Option) (*model.LinkResponse, error)
GenerateH5Code(ctx context.Context, dsi, sourceID string, opt ...model.Option) (*model.QrcodeResponse, error)
GenerateMiniCode(ctx context.Context, dsi, sourceID string, opt ...model.Option) (*model.QrcodeResponse, error)
GeneratePoster(ctx context.Context, dsi, sourceID string, opt ...model.Option) (*model.PosterResponse, error)
@ -71,6 +72,23 @@ func (s client) GenerateMiniLink(ctx context.Context, activityID, promotionID in
return result, err
}
// GenerateAlipayMiniLink 生成支付宝小程序页面推广路径
func (s client) GenerateAlipayMiniLink(ctx context.Context, activityID, promotionID int64, sourceID string, opt ...model.Option) (*model.LinkResponse, error) {
body := map[string]interface{}{
"activity_id": activityID,
"link_type": "alipay_mini",
"promotion_id": promotionID,
"source_id": sourceID,
}
response, err := util.Post(ctx, s.AppKey, s.AccessKey, consts.GenerateLinkUrl, body, opt...)
if err != nil {
return nil, err
}
result := &model.LinkResponse{}
err = json.Unmarshal(response, result)
return result, err
}
// GenerateH5Code 生成h5二维码需先取链得到dsi
func (s client) GenerateH5Code(ctx context.Context, dsi, sourceID string, opt ...model.Option) (*model.QrcodeResponse, error) {
param := map[string]interface{}{

View File

@ -25,7 +25,7 @@ type ResponseOrderItem struct {
CpsProfit int64 `json:"cps_profit"`
// CPA返佣金额单位
CpaProfit int64 `json:"cpa_profit"`
// CPA类型
// CPA类型cpa_normal-普通CPA新用户奖励order_cnt_eq-冲单奖
CpaType string `json:"cpa_type"`
// 推送状态: 1.已预估归因 2.预估订单已推送 3.预估订单推送失败 4.结算已提交 5.结算提交中 6.结算取消 7.结算成功 8.结算失败
Status int `json:"status"`

1
util/xerror/error.go Normal file
View File

@ -0,0 +1 @@
package xerror