From 08359eefcceed6591367e557b95682192d2cf18d Mon Sep 17 00:00:00 2001 From: wukesheng Date: Sun, 14 Jul 2024 22:14:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E7=A8=8Bapi=E5=AF=B9=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 3 ++ index.go | 9 ++++ platform/tong-cheng/api.go | 90 +++++++++++++++++++++++++++++++++ platform/tong-cheng/api_test.go | 68 +++++++++++++++++++++++++ platform/tong-cheng/client.go | 36 +++++++++++++ platform/tong-cheng/consts.go | 26 ++++++++++ platform/tong-cheng/sign.go | 1 + platform/tong-cheng/types.go | 90 +++++++++++++++++++++++++++++++++ 8 files changed, 323 insertions(+) create mode 100644 platform/tong-cheng/api.go create mode 100644 platform/tong-cheng/api_test.go create mode 100644 platform/tong-cheng/client.go create mode 100644 platform/tong-cheng/consts.go create mode 100644 platform/tong-cheng/sign.go create mode 100644 platform/tong-cheng/types.go diff --git a/go.mod b/go.mod index b493a18..95d1a48 100644 --- a/go.mod +++ b/go.mod @@ -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 ) diff --git a/index.go b/index.go index f388023..734856f 100644 --- a/index.go +++ b/index.go @@ -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) +} diff --git a/platform/tong-cheng/api.go b/platform/tong-cheng/api.go new file mode 100644 index 0000000..b4dc4b8 --- /dev/null +++ b/platform/tong-cheng/api.go @@ -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 +} diff --git a/platform/tong-cheng/api_test.go b/platform/tong-cheng/api_test.go new file mode 100644 index 0000000..476b211 --- /dev/null +++ b/platform/tong-cheng/api_test.go @@ -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)) +} diff --git a/platform/tong-cheng/client.go b/platform/tong-cheng/client.go new file mode 100644 index 0000000..b748e3a --- /dev/null +++ b/platform/tong-cheng/client.go @@ -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", + }, + } +} diff --git a/platform/tong-cheng/consts.go b/platform/tong-cheng/consts.go new file mode 100644 index 0000000..a22c57b --- /dev/null +++ b/platform/tong-cheng/consts.go @@ -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 +) diff --git a/platform/tong-cheng/sign.go b/platform/tong-cheng/sign.go new file mode 100644 index 0000000..5f3b63c --- /dev/null +++ b/platform/tong-cheng/sign.go @@ -0,0 +1 @@ +package tong_cheng diff --git a/platform/tong-cheng/types.go b/platform/tong-cheng/types.go new file mode 100644 index 0000000..bd8b26f --- /dev/null +++ b/platform/tong-cheng/types.go @@ -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:旧数据 +}