同程api对接

This commit is contained in:
wukesheng 2024-07-14 22:14:27 +08:00
parent cdb09a992f
commit 08359eefcc
8 changed files with 323 additions and 0 deletions

3
go.mod
View File

@ -12,6 +12,8 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)
require google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.15.0 // indirect
@ -26,5 +28,6 @@ require (
go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/sys v0.11.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -10,6 +10,7 @@ import (
"gitee.com/chengdu-lenntc/third-platform-sdk/platform/meituan-media"
meituanunion "gitee.com/chengdu-lenntc/third-platform-sdk/platform/meituan-union"
t3_union "gitee.com/chengdu-lenntc/third-platform-sdk/platform/t3-union"
tong_cheng "gitee.com/chengdu-lenntc/third-platform-sdk/platform/tong-cheng"
)
// Platform 第三方平台
@ -28,6 +29,8 @@ const (
PlatformMeituanMedia = "meituan_media"
// PlatformJutuike 聚推客
PlatformJutuike = "jutuike"
// PlatformTongCheng 同程酒店
PlatformTongCheng = "tong_cheng"
)
// PlatformNameMap 平台名称
@ -39,6 +42,7 @@ var PlatformNameMap = map[string]string{
PlatformT3Union: "t3联盟",
PlatformMeituanMedia: "美团-美天赚",
PlatformJutuike: "聚推客",
PlatformTongCheng: "同程酒店",
}
// GetPlatformName 获取平台名称
@ -80,3 +84,8 @@ func NewMeituanMediaApi(log logx.Logger, conf meituan_media.AuthConfig) meituan_
func NewJutuikeApi(log logx.Logger, conf jutuike.AuthConfig) jutuike.JutuikeApi {
return jutuike.NewApiClient(log, conf)
}
// NewTongChengApi 同程酒店
func NewTongChengApi(log logx.Logger, conf tong_cheng.AuthConfig) tong_cheng.TongChengApi {
return tong_cheng.NewApiClient(log, conf)
}

View File

@ -0,0 +1,90 @@
package tong_cheng
import (
"context"
"crypto/md5"
"errors"
"fmt"
"time"
"github.com/zeromicro/go-zero/core/logx"
"gitee.com/chengdu-lenntc/third-platform-sdk/client"
"gitee.com/chengdu-lenntc/third-platform-sdk/util"
)
// TongChengApi 同程酒店的api
// Api defines the interface of tong-cheng api
type TongChengApi interface {
// GenerateLink 生成链接
GenerateLink(ctx context.Context, req GenerateLinkRequest, env string) (*ExternalChannelConfigResponse, error)
// QueryOrderList 查询订单列表
QueryOrderList(ctx context.Context, req QueryOrderListRequest, env string) (*ExternalOrderData, error)
}
type tongChengApiImpl struct {
log logx.Logger
client *Client
}
func newTongChengApiImpl(log logx.Logger, client *Client) TongChengApi {
return &tongChengApiImpl{
log: log,
client: client,
}
}
// GenerateLink 生成短链
func (t *tongChengApiImpl) GenerateLink(ctx context.Context, req GenerateLinkRequest, env string) (*ExternalChannelConfigResponse, error) {
var url string
token := t.client.authConfig.Token
tn := time.Now()
actionTime := tn.Unix()
h := md5.New()
h.Write([]byte(fmt.Sprintf("%s%d", token, actionTime)))
queryArgs := &GetExternalChannelConfigReq{
ActionTime: tn.Unix(),
Token: token,
Code: string(h.Sum(nil)),
Trackid: req.Trackid,
}
args := util.StructToMap(queryArgs)
request := &client.HttpRequest{Headers: t.client.headers, QueryArgs: args}
response := new(GetExternalChannelConfigResp)
if env == EnvHuidu {
url = HDApiDomain + GetLinkUri
} else {
url = ApiDomain + GetLinkUri
}
if err := t.client.HttpGet(url, request, &client.HttpResponse{Result: response}); err != nil {
return nil, err
}
if response.Code != 200 {
t.log.WithFields(logx.LogField{Key: "data", Value: map[string]any{"req": req, "resp": response}}).
Errorf("[tongChengApiImpl][GenerateLink] response result error: %s", response.Msg)
return nil, errors.New(response.Msg)
}
return response.Data, nil
}
// QueryOrderList 查询订单列表
func (t *tongChengApiImpl) QueryOrderList(ctx context.Context, req QueryOrderListRequest, env string) (*ExternalOrderData, error) {
var url string
args := util.StructToMap(req)
request := &client.HttpRequest{Headers: t.client.headers, QueryArgs: args}
response := new(GetExternalOrderResp)
if env == EnvHuidu {
url = HDApiDomain + GetOrderListUri
} else {
url = ApiDomain + GetOrderListUri
}
if err := t.client.HttpGet(url, request, &client.HttpResponse{Result: response}); err != nil {
return nil, err
}
if response.Code != 200 {
t.log.WithFields(logx.LogField{Key: "data", Value: map[string]any{"req": req, "resp": response}}).
Errorf("[tongChengApiImpl][QueryOrderList] response result error: %s", response.Msg)
return nil, errors.New(response.Msg)
}
return response.Data, nil
}

View File

@ -0,0 +1,68 @@
package tong_cheng
import (
"context"
"encoding/json"
"testing"
"github.com/stretchr/testify/suite"
"github.com/zeromicro/go-zero/core/logx"
)
// api-单元测试
type apiClientSuite struct {
suite.Suite
api TongChengApi
}
func TestApiClient(t *testing.T) {
suite.Run(t, new(apiClientSuite))
}
func (a *apiClientSuite) SetupSuite() {
log := logx.WithContext(context.Background())
apiClient := NewApiClient(log, AuthConfig{
Token: "dfae91a85341865b",
})
a.api = apiClient
}
func (a *apiClientSuite) Test_GenerateLink() {
req := GenerateLinkRequest{
Trackid: "elong_hotel",
}
result, err := a.api.GenerateLink(context.Background(), req, "huidu")
if !a.NoError(err) {
a.T().Errorf("========[Test_GenerateLink] response error:%s", err)
return
}
resultByte, err := json.Marshal(result)
if err != nil {
a.T().Errorf("========[Test_GenerateLink] json_marshal error:%s", err)
return
}
a.T().Logf("=====[Test_GenerateLink] result: %s", string(resultByte))
}
func (a *apiClientSuite) Test_QueryOrderList() {
req := QueryOrderListRequest{
AppId: "",
Trackid: "",
BeginDate: "2024-07-01 00:00:00",
EndDate: "2024-07-01 23:59:59",
Update: 1,
PageIndex: 0,
PageSize: 1,
}
result, err := a.api.QueryOrderList(context.Background(), req, "huidu")
if !a.NoError(err) {
a.T().Errorf("========[Test_QueryOrderList] response error:%s", err)
return
}
resultByte, err := json.Marshal(result)
if err != nil {
a.T().Errorf("========[Test_QueryOrderList] json_marshal error:%s", err)
return
}
a.T().Logf("=====[Test_QueryOrderList] result: %s", string(resultByte))
}

View File

@ -0,0 +1,36 @@
package tong_cheng
import (
"github.com/zeromicro/go-zero/core/logx"
"gitee.com/chengdu-lenntc/third-platform-sdk/client"
)
// AuthConfig api鉴权参数
type AuthConfig struct {
Token string // 分配的token
}
// 连接第三方平台的client
type Client struct {
log logx.Logger
authConfig AuthConfig
client.HttpClient
headers map[string]string
}
func NewApiClient(log logx.Logger, conf AuthConfig) TongChengApi {
clt := newClient(log, conf)
return newTongChengApiImpl(log, clt)
}
func newClient(log logx.Logger, conf AuthConfig) *Client {
return &Client{
log: log,
authConfig: conf,
HttpClient: client.NewHttpClient(log),
headers: map[string]string{
"Content-Type": "application/json",
},
}
}

View File

@ -0,0 +1,26 @@
package tong_cheng
// 相关地址
const (
SiteDomain = "" // Domain 后台域名
SiteUrl = "" // SiteUrl 后台地址
DocUrl = "" // DocUrl 文档地址
ApiDocUrl = "" // ApiDocUrl api文档地址
)
// header头信息
const ()
// 环境
const (
EnvProd = "prod" // 正式环境
EnvHuidu = "huidu" // 灰度
)
// 接口地址
const (
HDApiDomain = "https://mp-blindbox-hd.elong.com" // Domain api域名 (灰度环境)
ApiDomain = "https://mp-blindbox.elong.com" // api域名正式环境
GetLinkUri = "/nopaymentorder/externalorder/getExternalChannelConfig" // 生成跳转链接uri
GetOrderListUri = "/nopaymentorder/externalorder/getExternalOrder" // 获取订单uri
)

View File

@ -0,0 +1 @@
package tong_cheng

View File

@ -0,0 +1,90 @@
package tong_cheng
import (
"time"
"google.golang.org/genproto/googleapis/type/decimal"
)
type CommonResponse struct {
Code int32 `json:"code"` // 状态码200为正常
Msg string `json:"msg"` // 返回信息
}
// 生成链接请求
type GenerateLinkRequest struct {
Trackid string `json:"trackid"` // 跟踪id,排查问题使用guid即可
}
// 获取外部渠道配置请求
type GetExternalChannelConfigReq struct {
ActionTime int64 `json:"action_time"` // 必传,请求时间戳
Token string `json:"token"` // 必传token
Code string `json:"code"` // 必传,校验参数
Trackid string `json:"trackid"` // 必传跟踪id,排查问题使用guid即可
}
// 获取外部渠道配置响应
type GetExternalChannelConfigResp struct {
CommonResponse
Data *ExternalChannelConfigResponse `json:"data"` // 数据
}
// 获取外部渠道配置数据
type ExternalChannelConfigResponse struct {
ActivityUrl string `json:"activityUrl"` // 渠道方合作页地址
AppId string `json:"appId"` // appId接口查询验证使用
AppSecret string `json:"appSecret"` // appSecret密钥验证使用
GetOrderServiceUrl string `json:"getOrderServiceUrl"` // 渠道方主动查询地址
PushOrderServiceUrl string `json:"pushOrderServiceUrl"` // 渠道方推送地址
OtherActivityUrls []*OtherActivityUrl `json:"otherActivityUrls"` // 其他的渠道方合作页地址
}
// 其他的渠道方合作页地址
type OtherActivityUrl struct {
Name string `json:"name"` // 合作页地址名称
ActivityUrl string `json:"activityUrl"` // 渠道方合作页地址
}
// 获取外部订单请求
type QueryOrderListRequest struct {
AppId string `json:"appId"` // 必传分配token查询接口提供的appId(getExternalChannelConfig接口返回的appId)
Trackid string `json:"trackid"` // 必传跟踪id,排查问题使用guid即可
BeginDate string `json:"begin_date"` // 订单更新时间查询起始,精确到秒, yyyy-MM-dd HH:mm:ss除了传订单号外其他查询必传
EndDate string `json:"end_date"` // 订单更新时间查询结束,精确到秒, yyyy-MM-dd HH:mm:ss除了传订单号外其他查询必传
OrderId string `json:"order_id"` // 指定订单号查询,返回该订单的最新详情
Update int32 `json:"update"` // 0:仅已支付的订单, 1:所有状态订单, 默认查所有传1
PageIndex int32 `json:"page_index"` // 分页index从0开始除了传订单号外其他查询必传
PageSize int32 `json:"page_size"` // 分页条数(除了传订单号外,其他查询必传)
}
// 获取外部订单响应
type GetExternalOrderResp struct {
CommonResponse
Data *ExternalOrderData `json:"data"` // 数据
}
type ExternalOrderData struct {
ExternalOrderDataList []*ExternalOrder `json:"externalOrderDataList"` // 订单数据
}
// 订单详情
type ExternalOrder struct {
ExtendInfo string `json:"extendInfo"` // 订单附加信息json格式
HotelCityName string `json:"hotelCityName"` // 酒店所在城市名称
HotelName string `json:"hotelName"` // 酒店名称
OrderCheckIn string `json:"orderCheckIn"` // 入住日期
OrderCheckOut string `json:"orderCheckOut"` // 离店时间
OrderCreateTime string `json:"orderCreateTime"` // 订单创建时间date-time
OrderModifyTime string `json:"orderModifyTime"` // 订单更新时间date-time
OrderNo string `json:"orderNo"` // 订单号
OrderPayAmount decimal.Decimal `json:"orderPayAmount"` // 订单实付金额
OrderPayTime time.Time `json:"orderPayTime"` // 订单支付时间 date-time
OrderStatus int32 `json:"orderStatus"` // 订单组推送的订单状态(1: 已支付 2:已离店 3:已取消)
OrderCommission decimal.Decimal `json:"orderCommission"` // 订单佣金
Uid string `json:"uid"` // 第三方用户id
HotelProvinceName string `json:"hotelProvinceName"` // 酒店所在省份
RoomNights int32 `json:"roomNights"` // 入住间夜
RoomCount int32 `json:"roomCount"` // 入住房间数量
HourRoom int32 `json:"hourRoom"` // 是否钟点房1:是 0:不是 -1:旧数据
}