新增抖音授权登录

This commit is contained in:
邹宗楠
2022-04-14 17:02:41 +08:00
parent 65852ad289
commit 13757d515d
13 changed files with 1307 additions and 5 deletions

View File

@@ -204,4 +204,8 @@ func TestDaDa(t *testing.T) {
fmt.Println("美团", 1&0)
fmt.Println("达达", 2&0)
fmt.Println("蜂鸟", 4&0)
fmt.Println("蜂鸟", 19&16 != 0)
fmt.Println("蜂鸟", 23&16 != 0)
fmt.Println("蜂鸟", 21&16 != 0)
fmt.Println("蜂鸟", 11&16 != 0)
}

View File

@@ -228,10 +228,6 @@ func (a *API) signParams(params url.Values) string {
}
func (a *API) AccessAPI2(baseURL, action string, params map[string]interface{}) (retVal *ResponseResult, err error) {
// if params == nil {
// panic("params is nil!")
// }
params2 := utils.Map2URLValues(params)
if baseURL == mtpsAPIURL {
params2.Set("appkey", a.appKey)
@@ -241,7 +237,6 @@ func (a *API) AccessAPI2(baseURL, action string, params map[string]interface{})
} else if a.GetCookieCount() == 0 {
return nil, fmt.Errorf("需要设置Store Cookie才能使用此方法")
}
// baseapi.SugarLogger.Debug(params2.Encode())
err = platformapi.AccessPlatformAPIWithRetry(a.client,
func() *http.Request {

View File

@@ -0,0 +1,19 @@
package mtpsapi
const (
DaDaCode = 10002 // 达达配送
FnPsCode = 10004 // 蜂鸟配送
MTPsCode = 10032 // 美团配送
MyselfPsCode = 10015 // 自送
)
type RiderInfo struct {
OrderId string `json:"order_id"` // 发单平台订单id(美团,京西,京,京东)
ThirdCarrierOrderId string `json:"third_carrier_order_id"` // 京西平台id
CourierName string `json:"courier_name"` // 骑手名称
CourierPhone string `json:"courier_phone"` // 骑手电话
LogisticsProviderCode string `json:"logistics_provider_code"` // 配送平台code 10001-顺丰, 10002-达达, 10003-闪送, 10004-蜂鸟, 10005 UU跑腿,10006 快跑者, 10007 极客快送,10008-点我达,10009 同达, 10010-生活半径,10011 邻趣,10012 趣送, 10013 快服务 10014 菜鸟新配盟 10015 商家自建配送 10016 风先生,10017-其他,10032-美团跑腿
LogisticsStatus int `json:"logistics_status"` // 配送状态
Latitude string `json:"latitude"` // 骑手当前的纬度,美团使用的是高德坐标系。
Longitude string `json:"longitude"` // 骑手当前的经度,美团使用的是高德坐标系。
}

View File

@@ -659,3 +659,10 @@ func (a *API) OrderUpdateTip(orderID int64, tipAmount float64) (err error) {
_, err = a.AccessAPI("order/zhongbao/update/tip", true, params)
return err
}
// 美团外卖自配送商家同步发货状态和配送信息(推荐)
// https://waimaiopen.meituan.com/api/v1/ecommerce/order/logistics/sync
func (a *API) OrderStatusAndPsInfo(params map[string]interface{}) (err error) {
_, err = a.AccessAPI("ecommerce/order/logistics/sync", false, params)
return err
}

View File

@@ -0,0 +1,198 @@
package fnpsapi
import (
"encoding/json"
"git.rosy.net.cn/baseapi"
"io/ioutil"
"net/http"
)
const (
OrderStatus = "orderStatusNotify" // 订单状态回调
AbnormalStatus = "abnormalReportNotify" // 异常报备回调
CookingFinishStatus = "cookingFinishNotify" // 商户出餐回调
ChainstoreStatus = "chainstoreStatusNotify" // 门店状态变更回调
ChainstoreServiceStatus = "chainstoreServiceStatusNotify" // 门店采购服务变更回调
NoServiceStatus = "noServiceNotify" // 城市屏蔽区域调整回调通知
)
var (
SuccessResponse = &CallbackResponse{Code: 200}
SignatureIsNotOk = &CallbackResponse{Code: -1}
)
type CallbackResponse struct {
Code int `json:"code"`
}
func Err2CallbackResponse(err error, data string) *CallbackResponse {
if err == nil {
return SuccessResponse
}
return &CallbackResponse{
Code: -1,
}
}
type ShortStatus struct {
AppId string `json:"app_id"`
Signature string `json:"signature"`
Timestamp string `json:"timestamp"`
BusinessData string `json:"business_data"`
}
//#region 订单
// 订单状态
type OrderStatusNottify struct {
CallbackBusinessType string `json:"callback_business_type"`
Param *OrderCallbackParam `json:"param"`
}
// 订单状态回调paramter
type OrderCallbackParam struct {
OrderId int64 `json:"order_id"` // 订单号
AppId string `json:"app_id"` // 应用id
PartnerOrderCode string `json:"partner_order_code"` // 外部订单号
OrderStatus int `json:"order_status"` // 订单状态 订单生成0运单生成成功120骑手接单80骑手到 店2配送中3已完成4已取消5配送异常
CarrierDriverId int64 `json:"carrier_driver_id"` // 骑手id
CarrierLat string `json:"carrier_lat"` // 坐标高德(不要使用)
CarrierLng string `json:"carrier_lng"` // 坐标高德(不要使用)
CarrierDriverName string `json:"carrier_driver_name"` // 骑手姓名
CarrierDriverPhone string `json:"carrier_driver_phone"` // 骑手电话
Description string `json:"description"` // 描述
ErrorCode string `json:"error_code"` // 异常code
ErrorScene string `json:"error_scene"` // 异常描述
DetailDescription string `json:"detail_description"` // 详情描述
PushTime int64 `json:"push_time"` // 状态推送时间 (毫秒)
Transfer int `json:"transfer"` // 转单标识 转单标识 1 是转单 0非转单
}
//#endregion
// 门店状态回调
type ChainstoreStatusNotify struct {
CallbackBusinessType string `json:"callback_business_type"`
Param *ChainstoreParam `json:"param"`
}
// 门店状态回调paramter
type ChainstoreParam struct {
MerchantId string `json:"merchant_id"` // 商户id
ChainStoreId string `json:"chain_store_id"` // 蜂鸟门店id
OutShopCode string `json:"out_shop_code"` // 外部门店编码
Status string `json:"status"` // 门店认证状态
ModifyStatus string `json:"modify_status"` // 门店修改状态
Remark string `json:"remark"` // 门店认证、修改等驳回时返回原因
}
// 出餐回调
type CookingFinishNotify struct {
OrderId int64 `json:"order_id"` // 订单号
AppId string `json:"app_id"` // 应用id
PartnerOrderCode string `json:"partner_order_code"` // 外部订单号
ChainStoreId string `json:"chain_store_id"` // 蜂鸟门店id
MerchantId string `json:"merchant_id"` // 商户id
CookingFinishTime int64 `json:"cooking_finish_time"` // 状态推送时间 (毫秒)
}
// 异常状态回掉
type AbnormalStatusNotify struct {
CallbackBusinessType string `json:"callback_business_type"`
Param *AbnormalReportNotify `json:"param"`
}
// 异常状态回调
type AbnormalReportNotify struct {
OrderId int64 `json:"order_id"` // 订单号
AppId string `json:"app_id"` // 应用id
PartnerOrderCode string `json:"partner_order_code"` // 外部订单号
CarrierDriverId int64 `json:"carrier_driver_id"` // 骑手id
Longitude string `json:"longitude"` // 纬度
Latitude string `json:"latitude"` // 门店纬度
AbnormalCode string `json:"abnormal_code"` // 异常报备code
AbnormalDesc string `json:"abnormal_desc"` // 异常报备描述
AbnormalReportTime int64 `json:"abnormal_report_time"` // 异常报备时间 毫秒
}
// 获取门店状态回调消息
func (a *API) GetChainstoreStatusNotify(request *http.Request) (shopStatusMsg *ChainstoreStatusNotify, callbackResponse *CallbackResponse) {
data, err := ioutil.ReadAll(request.Body)
if err != nil {
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
storeNotify := &ShortStatus{}
if err := json.Unmarshal(data, &storeNotify); err != nil {
baseapi.SugarLogger.Debugf("FN GetChainstoreStatusNotify failed with err:%v", err)
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
fnNotify := &ChainstoreStatusNotify{}
if err := json.Unmarshal([]byte(storeNotify.BusinessData), fnNotify); err != nil {
baseapi.SugarLogger.Debugf("FN callback string to GetChainstoreStatusNotify failed with err:%v", err)
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
return fnNotify, SuccessResponse
}
// 获取订单状态回调消息
func (a *API) GetChainOrderStatusNotify(request *http.Request) (shopStatusMsg *OrderStatusNottify, callbackResponse *CallbackResponse) {
data, err := ioutil.ReadAll(request.Body)
if err != nil {
baseapi.SugarLogger.Debugf("FN GetChainOrderStatusNotify failed with No result msg err:%v", err)
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
result := &ShortStatus{}
if err := json.Unmarshal(data, &result); err != nil {
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
orderResult := &OrderStatusNottify{}
if err := json.Unmarshal([]byte(result.BusinessData), orderResult); err != nil {
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
return orderResult, SuccessResponse
}
// 异常配送
func (a *API) GetChainAbnormaltatusNotify(request *http.Request) (shopStatusMsg *AbnormalStatusNotify, callbackResponse *CallbackResponse) {
data, err := ioutil.ReadAll(request.Body)
if err != nil {
baseapi.SugarLogger.Debugf("FN GetChainOrderStatusNotify failed with No result msg err:%v", err)
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
storeNotify := &ShortStatus{}
if err := json.Unmarshal(data, &storeNotify); err != nil {
baseapi.SugarLogger.Debugf("FN GetShopStatusCallbackMsg failed with err:%v", err)
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
fnNotify := &AbnormalStatusNotify{}
if err := json.Unmarshal([]byte(storeNotify.BusinessData), fnNotify); err != nil {
baseapi.SugarLogger.Debugf("FN callback string to ChainstoreStatusNotify failed with err:%v", err)
callbackResponse = &CallbackResponse{Code: -1}
return nil, callbackResponse
}
return fnNotify, SuccessResponse
}
func (a *API) CheckCallbackValidation(request *http.Request) (callbackResponse *CallbackResponse) {
err := request.ParseForm()
if err != nil {
callbackResponse = Err2CallbackResponse(err, "")
}
return callbackResponse
}

274
platformapi/sfps/order.go Normal file
View File

@@ -0,0 +1,274 @@
package fnpsapi
//
//import (
// "encoding/json"
// "errors"
// "git.rosy.net.cn/baseapi/utils"
// "time"
//)
//
//const (
// OrderCancelReson0 = 0 // 0:其它(必填原因)必须填写原因
// OrderCancelReson1 = 1 // 1:物流原因:订单长时间未分配骑手
// OrderCancelReson4 = 4 // 4:商品缺货/无法出货/已售完,
// OrderCancelReson6 = 6 // 6:商户发错单,
// OrderCancelReson7 = 7 // 7:商户/顾客自身定位错误,
// OrderCancelReson8 = 8 // 8:商户改其他第三方配送,
// OrderCancelReson9 = 9 // 9:顾客下错单/临时不想要了,
// OrderCancelReson10 = 10 // 10:顾客自取/不在家/要求另改时间配送0类型已下线
// OrderCancelReson32 = 32 // 32:订单信息填写错误
// OrderCancelReson36 = 36 // 36:重复下单了
// OrderCancelReson2 = 2 // 2:物流原因:分配骑手后,骑手长时间未取件(类型已下线)
// OrderCancelReson3 = 3 // 3:物流原因:骑手告知不配送,让取消订单(类型已下线)
// OrderCancelReson5 = 5 // 5:商户联系不上门店/门店关门了(类型已下线)
//
// OrderStatusAcceptCreate = 0 //订单生成
// OrderStatusAcceptCacle = 4 //订单取消
// OrderStatusAccept = 1 //系统已接单
// OrderStatusAssigned = 20 //已分配骑手
// OrderStatusArrived = 80 //已到店
// OrderStatusDelivering = 2 //配送中
// OrderStatusDelivered = 3 //已送达
// OrderStatusException = 5 //异常
//)
//
//// 蜂鸟预下单
//func (a *API) PreCreateByShopFn(basicParams *PreCreateOrder) (deliveryFee, baseDeliveryFee int64, err error) {
// preOrder := a.MakeFnRequestHead()
// bytes, err := json.Marshal(basicParams)
// if err != nil {
// return 0, 0, err
// }
// preOrder["business_data"] = string(bytes)
// result, err := a.AccessAPI(ApiURL, "preCreateOrder", RequestPost, preOrder)
// if err != nil {
// return 0, 0, err
// }
//
// preOrderResult := PreCreateOrderResp{}
// if err := json.Unmarshal([]byte(result["business_data"].(string)), &preOrderResult); err != nil {
// return 0, 0, err
// }
//
// // 返回所有可选的商品列表,每项包含当前使用该商品下单时对应的价格等信息,(其中不可用的商品会返回不可用原因) 可挑选其中一个可用的商品进行正式下单。
// var deliveryFeeFn int64
// var baseDeliveryFeeFn int64
// for _, v := range preOrderResult.GoodsInfos {
// if v.IsValid != 1 {
// continue
// }
// deliveryFeeFn = v.ActualDeliveryAmountCent
// baseDeliveryFeeFn = v.TotalDeliveryAmountCent
// }
//
// // 异常检测
// if deliveryFeeFn == 0 && baseDeliveryFeeFn == 0 {
// return 0, 0, errors.New(preOrderResult.GoodsInfos[0].DisableReason)
// }
// return deliveryFeeFn, baseDeliveryFeeFn, nil
//}
//
//// 蜂鸟正式下单
//func (a *API) CreateOrder(createOrderParam *CreateOrderReqParam) (result string, err error) {
// orderHead := a.MakeFnRequestHead()
// bytes, err := json.Marshal(createOrderParam)
// if err != nil {
// return "", err
// }
// orderHead["business_data"] = string(bytes)
// resultData, err := a.AccessAPI(ApiURL, "createOrder", RequestPost, orderHead)
// if orderId, ok := resultData["business_data"]; ok {
// res := &CreateOrderRes{}
// if err := json.Unmarshal([]byte(utils.Interface2String(orderId)), res); err != nil {
// return "", err
// }
// return utils.Int64ToStr(res.OrderId), nil
// }
// return "", err
//}
//
//// addTip 加小费接口
//func (a *API) AddTip(req *AddTipRes) (err error) {
// if req.PartnerOrderCode == "" && req.OrderId == "" {
// return errors.New("内部订单号或者外部订单号比填写一个")
// }
//
// orderHead := a.MakeFnRequestHead()
// addTipString, err := json.Marshal(req)
// if err != nil {
// return err
// }
//
// orderHead["businessData"] = string(addTipString)
// if _, err = a.AccessAPI(ApiURL, "addTip", RequestPost, orderHead); err != nil {
// return err
// }
// return nil
//}
//
//// getCancelReasonList 获取可用取消原因列表(暂油前端写死)
//func (a *API) GetCancelReasonList(req *GetOrderDetailReq) (result *GetCancelReasonListRes, err error) {
// if req.PartnerOrderCode == "" && req.OrderId == "" {
// return nil, errors.New("内部订单号或者外部订单号比填写一个")
// }
//
// a.timestamp = time.Now().Unix() * 1000
// orderHead := a.MakeFnRequestHead()
// business, err := json.Marshal(req)
// if err != nil {
// return nil, err
// }
// orderHead["businessData"] = string(business)
// data, err := a.AccessAPI(ApiURL, "getCancelReasonList", RequestPost, orderHead)
// if err != nil {
// return nil, err
// }
//
// cancel := make(map[string]*GetCancelReasonListRes, 0)
// if k, ok := data["business_data"]; ok {
// if err := json.Unmarshal([]byte(utils.Interface2String(k)), cancel); err != nil {
// return nil, err
// }
// }
// return cancel["cancel_reason_list"], nil
//}
//
//// preCancelOrder 预取消订单接口,获取取消订单需要扣除的金额
//func (a *API) PreCancelOrder(req *PreCancelOrderReq) (actualCancelCostCent int64, err error) {
// if req.PartnerOrderCode == "" && req.OrderId == "" {
// return 0, errors.New("内部订单号或者外部订单号比填写一个")
// }
// orderHead := a.MakeFnRequestHead()
// business, err := json.Marshal(req)
// if err != nil {
// return 0, err
// }
// orderHead["businessData"] = string(business)
//
// data, err := a.AccessAPI(ApiURL, "preCancelOrder", RequestPost, orderHead)
// if err != nil {
// return 0, err
// }
//
// if k, ok := data["businessData"]; ok {
// return utils.MustInterface2Int64(k), nil
// }
// return
//}
//
//// cancelOrder 取消订单
//func (a *API) CancelOrder(req *CancelOrderReq) (err error) {
// if req.PartnerOrderCode == "" && req.OrderId == "" {
// return errors.New("内部订单号或者外部订单号比填写一个")
// }
// if req.OrderCancelCode == 0 && req.OrderCancelOtherReason == "" {
// req.OrderCancelOtherReason = "暂时不想要了"
// }
//
// orderHead := a.MakeFnRequestHead()
// business, err := json.Marshal(req)
// if err != nil {
// return err
// }
// orderHead["business_data"] = string(business)
//
// if _, err := a.AccessAPI(ApiURL, "cancelOrder", RequestPost, orderHead); err != nil {
// return err
// }
//
// return
//}
//
//// 查询订单详情接口
//func (a *API) QueryOrder(partnerOrderCode string) (result *GetOrderDetailRes, err error) {
// orderHead := a.MakeFnRequestHead()
// bytes, err := json.Marshal(&GetOrderDetailReq{PartnerOrderCode: partnerOrderCode})
// if err != nil {
// return nil, err
// }
//
// orderHead["business_data"] = string(bytes)
// data, err := a.AccessAPI(ApiURL, "getOrderDetail", RequestPost, orderHead)
// if err != nil {
// return nil, err
// }
//
// fnResult := &GetOrderDetailRes{}
// if err := json.Unmarshal([]byte(data["business_data"].(string)), &fnResult); err != nil {
// return nil, err
// }
// return fnResult, nil
//}
//
//// 查询骑手信息
//func (a *API) GetKnightInfo(req *GetOrderDetailReq) (result *GetKnightInfoRes, err error) {
// if req.PartnerOrderCode == "" && req.OrderId == "" {
// return nil, errors.New("内部订单号或者外部订单号比填写一个")
// }
//
// orderHead := a.MakeFnRequestHead()
// bytes, err := json.Marshal(req)
// if err != nil {
// return nil, err
// }
// orderHead["business_data"] = string(bytes)
//
// data, err := a.AccessAPI(ApiURL, "getKnightInfo", RequestPost, orderHead)
// if err != nil {
// return nil, err
// }
//
// fnResult := &GetKnightInfoRes{}
// if err := json.Unmarshal([]byte(utils.Interface2String(data["business_data"])), &fnResult); err != nil {
// return nil, err
// }
// return fnResult, nil
//}
//
//// 余额查询
//func (a *API) GetAmount() (outAmount map[string]interface{}, err error) {
// orderHead := a.MakeFnRequestHead()
// result, err := a.AccessAPI(ApiURL, "getAmount", RequestPost, orderHead)
// if err != nil {
// return nil, err
// }
// return result, err
//}
//
////order_cancel_reason_code 订单取消原因代码(1:用户取消,2:商家取消)
//// order_cancel_code 订单取消编码(
//// 1:物流原因:订单长时间未分配骑手,
//// 2:物流原因:分配骑手后,骑手长时间未取件 ,
//// 3:物流原因:骑手告知不配送,让取消订单,
//// 4:商品缺货/无法出货/已售完, 5:商户联系不上门店/门店关门了, 6:商户发错单,
//// 7:商户/顾客自身定位错误, 8:商户改其他第三方配送, 9:顾客下错单/临时不想要了,
//// 10:顾客自取/不在家/要求另改时间配送0类型已下线
//func (a *API) ComplaintOrder(req *ComplaintOrderReq) (err error) {
// if req.PartnerOrderCode == "" && req.OrderId == "" {
// return errors.New("内部订单号或者外部订单号比填写一个")
// }
// orderHead := a.MakeFnRequestHead()
// bytes, err := json.Marshal(req)
// if err != nil {
// return err
// }
// orderHead["businessData"] = string(bytes)
// _, err = a.AccessAPI(ApiURL, "cancelOrder", RequestPost, orderHead)
// return err
//}
//
//func (a *API) ComplaintRider(partnerOrderCode string, orderComplaintCode int) (err error) {
// orderHead := a.MakeFnRequestHead()
//
// bytes, err := json.Marshal(map[string]interface{}{
// "partner_order_code": partnerOrderCode,
// "order_complaint_code": orderComplaintCode,
// })
// if err != nil {
// return err
// }
// orderHead["businessData"] = string(bytes)
// _, err = a.AccessAPI(ApiURL, "cancelOrder", RequestPost, orderHead)
// return err
//}

159
platformapi/sfps/sf_base.go Normal file
View File

@@ -0,0 +1,159 @@
package fnpsapi
import (
"git.rosy.net.cn/baseapi/platformapi"
"net/http"
"sync"
)
const (
ApiURL = "https://openic.sf-express.com" // 正式环境
RequestPost = "POST"
)
// 物品类型product_type枚举值
const (
FastFood = 1 // 快餐
Drugs = 2 // 药品
DepartmentStore = 3 // 百货
OldClothes = 4 // 脏衣服收
NewClothes = 5 // 干净衣服派
Fresh = 6 // 生鲜
HighDrinks = 8 // 高端饮品
SiteInspection = 9 // 现场勘验
Express = 10 // 快递
File = 12 // 文件
Cake = 13 // 蛋糕
Flower = 14 // 鲜花
Digital = 15 // 数码
Clothing = 16 // 服装
Car = 17 // 汽配
Jewellery = 18 // 珠宝
Pizza = 20 // 披萨
ChineseFood = 21 // 中餐
FreshwaterFresh = 22 // 水产
DirectDelivery = 27 // 专人直送
MidRangeDrinks = 32 // 中端饮品
ConvenienceStore = 33 // 便利店
Bakeries = 34 // 面包糕点
HotPot = 35 // 火锅
licence = 36 // 证照
Crayfish = 40 // 烧烤小龙虾
OtherInfo = 41 // 外部落地配
AlcoholAndTobacco = 47 // 烟酒行
AdultEroticaProducts = 48 // 成人用品
Other = 99 // 其他
)
// 注册请求api
type API struct {
devId string `json:"dev_id"`
devKey string `json:"dev_key"`
signature string `json:"sign"`
pushTime int64 `json:"push_time"`
locker sync.RWMutex
client *http.Client
config *platformapi.APIConfig
}
/************************************************订单*****************************************************/
//#region 获取蜂鸟门店信息
// 创建订单
type CreateOrder struct {
// 必填
DevId int64 `json:"dev_id"` // 同城开发者ID
ShopId string `json:"shop_id"` // 店铺ID
ShopOrderId string `json:"shop_order_id"` // 商家订单号不允许重复
OrderSource string `json:"order_source"` // 订单接入来源 1美团2饿了么3百度4口碑其他请直接填写中文字符串值
LbsType int `json:"lbs_type"` // 坐标类型 1百度坐标2高德坐标
PayType int64 `json:"pay_type"` // 用户支付方式 1已付款 0货到付款
OrderTime int64 `json:"order_time"` // 用户下单时间 秒级时间戳
IsAppoint int `json:"is_appoint"` // 是否是预约单 0非预约单1预约单
IsInsured int64 `json:"is_insured"` // 是否保价0非保价1保价
IsPriorityAssign int64 `json:"is_priority_assign"` // 是否优先派单0否 1
IsPersonDirect int64 `json:"is_person_direct"` // 是否是专人直送订单01
PushTime int64 `json:"push_time"` // 推单时间 秒级时间戳
Version int64 `json:"version"` // 版本号 参照文档主版本号填写 如文档版本号1.7,version=17
Receive *ReceiveAddress `json:"receive"` // 收货人信息
Shop *SfShopInfo `json:"shop"` // 发货店铺信息 Obj详见shop结构 平台级开发者(如饿了么)需传入如无特殊说明此字段可忽略
OrderDetail *OrderDetails `json:"order_detail"` // 订单详情
MultiPickupInfo []*MultiPickupDetails `json:"multi_pickup_info"` // 多点取货信息
// 非必填
ShopType int64 `json:"shop_type"` // 店铺ID类型 1顺丰店铺ID 2接入方店铺ID
ShopPreparationTime int64 `json:"shop_preparation_time"` // 商家预计备餐时长(分10)
OrderSequence string `json:"order_sequence"` // 取货序号 与order_source配合使用 如饿了么10号单表示如下order_source=2;order_sequence=10。用于骑士快速寻找配送物
AppointType int `json:"appoint_type"` // 预约单类型 预约单的时候传入,1预约单送达单2预约单上门单
ExpectTime int64 `json:"expect_time"` // 用户期望送达时间 若传入自此段且时间大于配送时效则按照预约送达单处理时间小于配送时效按照立即单处理appoint_type=1时需必传,秒级时间戳;
ExpectPickupTime int64 `json:"expect_pickup_time"` // 用户期望上门时间 appoint_type=2时需必传,秒级时间戳
ShopExpectTime int64 `json:"shop_expect_time"` // 商家期望送达时间 只展示给骑士,不参与时效考核;秒级时间戳
Vehicle int `json:"vehicle"` // 配送交通工具01电动车2小轿车
DeclaredValue int64 `json:"declared_value"` // 保价金额(单位:分)
GratuityFee int64 `json:"gratuity_fee"` // 订单小费不传或者传0为不加小费 单位分加小费最低不能少于100分
Remark string `json:"remark"` // 订单备注
RiderPickMethod int64 `json:"rider_pick_method"` // 物流流向 1从门店取件送至用户 2从用户取件送至门店
ReturnFlag int `json:"return_flag"` // 返回字段控制标志位(二进制) 1:商品总价格2:配送距离4:物品重量8:起送时间16:期望送达时间32:支付费用64:实际支付金额128:优惠券总金额256:结算方式 例如全部返回为填入511
}
// 发货店铺信息,必填
type SfShopInfo struct {
ShopName string `json:"shop_name"` // 店铺名称
ShopPhone string `json:"shop_phone"` // 店铺电话
ShopAddress string `json:"shop_address"` // 店铺地址
ShopLng string `json:"shop_lng"` // 店铺经度
ShopLat string `json:"shop_lat"` // 店铺纬度
}
// 收货人信息
type ReceiveAddress struct {
// 必填
UserName string `json:"user_name"` // 用户姓名
UserPhone string `json:"user_phone"` // 用户电话
UserAddress string `json:"user_address"` // 用户地址
UserLng string `json:"user_lng"` // 用户经度
UserLat string `json:"user_lat"` // 用户纬度
// 非必填
CityName string `json:"city_name"` // 发单城市
}
// 订单详情
type OrderDetails struct {
// 必填
TotalPrice int64 `json:"total_price"` // 订单金额 分
ProductType int64 `json:"product_type"` // 物品类型 枚举值见下面定义
WeightGram int64 `json:"weight_gram"` // 物品重量(单位:克)
ProductNum int64 `json:"product_num"` // 物品个数
ProductTypeNum int64 `json:"product_type_num"` // 物品种类个数
ProductDetail []*ProductDetail `json:"product_detail"` // 物品详情数组结构详见product_detail结构
// 非必填
UserMoney int64 `json:"user_money"` // 用户实付商家金额(单位:分)
ShopMoney int `json:"shop_money"` // 商家实收用户金额(单位:分)
VolumeLitre int64 `json:"volume_litre"` // 物品体积(单位:升)
DeliveryMoney int64 `json:"delivery_money"` // 商家收取用户的配送费(单位:分)
}
// 购买物品详情清单
type ProductDetail struct {
// 必填
ProductName string `json:"product_name"` // 物品名称
ProductNum int64 `json:"product_num"` // 物品数量
// 非必填
ProductId int64 `json:"product_id"` // 物品ID
ProductPrice int64 `json:"product_price"` // 物品价格
ProductUnit string `json:"product_unit"` // 物品单位
ProductRemark string `json:"product_remark"` // 备注
ItemDetail string `json:"item_detail"` // 详情
}
// 取货地址详情
type MultiPickupDetails struct {
PickupShopAddress string `json:"pickup_shop_address"` // 取货点地址
PickupShopPhone string `json:"pickup_shop_phone"` // 取货点店铺手机号
PickupShopName string `json:"pickup_shop_name"` // 取货点店铺名称
PickupLng string `json:"pickup_lng"` // 取货点经度
PickupLat string `json:"pickup_lat"` // 取货点纬度
PickupProducts string `json:"pickup_products"` // 取货点店铺物品信息
}
//#endregion

208
platformapi/sfps/sf_test.go Normal file
View File

@@ -0,0 +1,208 @@
package fnpsapi
//
//import (
// "encoding/json"
// "fmt"
// "git.rosy.net.cn/baseapi"
// "go.uber.org/zap"
// "testing"
//)
//
//var (
// api *API
// sugarLogger *zap.SugaredLogger
//)
//
//func init() {
// logger, _ := zap.NewDevelopment()
// sugarLogger = logger.Sugar()
// baseapi.Init(sugarLogger)
//
// //api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu")
// //token, _ := api.GetAccessToken()
// //api.accessToken = token.BusinessDataObj.AccessToken
//}
//
//// 查询单个门店
//func TestQueryOneStore(t *testing.T) {
// api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "")
// token, err := api.GetAccessToken()
// api.accessToken = token.BusinessDataObj.AccessToken
// data, err := api.GetStore("209476483")
// fmt.Println(data)
// fmt.Println(err)
//}
//
//// 正式下单
//func TestCreateOrder(t *testing.T) {
// api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "")
// token, err := api.GetAccessToken()
// fmt.Println("22222222222", err)
// api.accessToken = token.BusinessDataObj.AccessToken
//
// aa := []*GoodsItemsList{
// {"白菜", 1, 100, 100, "30011", 1, "备注:大白菜"},
// //{"白菜2", 1, 100, 100, "30012", 1, "备注:大白菜2"},
// // {"白菜3", 1, 100, 100, "1004", 1, "备注:大白菜2"},
// }
// _, err = api.CreateOrder(&CreateOrderReqParam{
// PartnerOrderCode: "232232992229uue21",
// OrderType: 1,
// PositionSource: 3,
// ReceiverAddress: "四川成都",
// ReceiverLongitude: 116.307892,
// ReceiverLatitude: 40.039115,
// GoodsTotalAmountCent: 100,
// GoodsActualAmountCent: 100,
// GoodsWeight: 0.25,
// GoodsCount: 1,
// GoodsItemList: aa,
// ReceiverName: "刘磊",
// ReceiverPrimaryPhone: "18981810340",
// OutShopCode: "",
// ChainStoreId: "209476483",
// })
// fmt.Println(err)
//}
//
//// 创建门店,
//func TestCreateStore(t *testing.T) {
// api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu")
// token, _ := api.GetAccessToken()
// api.accessToken = token.BusinessDataObj.AccessToken
// err, _ := api.CreateStore(&CreateStoreBaseInfo{
// HeadShopName: "刘磊测试门店",
// ContactPhone: "18981810340",
// Address: "四川成都",
// Longitude: 104.094555,
// Latitude: 30.661382,
// PositionSource: 3,
// OutShopCode: "637910",
// CategoryID: "12",
// OwnerName: "刘磊",
// OwnerIDNum: "511324199308263974",
// HandheldLicencePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
// OwnerIDPicFrontHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
// OwnerIDPicBackHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
// CreditCode: "12345",
// BusinessLicencePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
//
// BranchShopName: "",
// ChainstoreType: 2,
// SettlementModel: "1",
// SettlementAccountID: "",
// FoodLicensePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
// SecondMedicalEquipmentLicensePicHash: "",
// MedicalInstitutionLicensePicHash: "",
// MedicalEquipmentLicensePicHash: "",
// MedicineLicensePicHash: "",
// TabacooLicensePicHash: "",
// })
// fmt.Println(err)
//}
//
//func TestUpdataStore(t *testing.T) {
// api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "cabrXQf9eFMVWVYg4hNlwu")
// token, _ := api.GetAccessToken()
// api.accessToken = token.BusinessDataObj.AccessToken
// err := api.UpdateStore(&UpdateStoreParam{
// ChainStoreID: 209636747,
// HeadShopName: "刘磊测试门店",
// ContactPhone: "18981810340",
// Address: "四川成都",
// Longitude: 104.094555,
// Latitude: 30.661382,
// PositionSource: 3,
// OutShopCode: "637910",
// CategoryID: "12",
// OwnerName: "刘磊",
// OwnerIDNum: "511324199308263974",
// HandheldLicencePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
// OwnerIDPicFrontHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
// OwnerIDPicBackHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
// CreditCode: "12345",
// BusinessLicencePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
//
// BranchShopName: "",
// ChainstoreType: 2,
// FoodLicensePicHash: "d7c64022f6458f9aa76968e01f5686c5.jpeg",
// SecondMedicalEquipmentLicensePicHash: "",
// MedicalInstitutionLicensePicHash: "",
// MedicalEquipmentLicensePicHash: "",
// MedicineLicensePicHash: "",
// TabacooLicensePicHash: "",
// })
// fmt.Println(err)
//}
//
//func TestClient(t *testing.T) {
// api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "51658", "4W4hqacKND6NOct5gCyjbT")
// token, err := api.GetAccessToken()
// api.accessToken = token.BusinessDataObj.AccessToken
// fmt.Println("token===", token.BusinessDataObj.AccessToken)
// fmt.Println("err=====", err)
//}
//
//// 预下单
//func TestGetOrder(t *testing.T) {
// api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "5375691", "")
// token, _ := api.GetAccessToken()
// api.accessToken = token.BusinessDataObj.AccessToken
//
// aa := []*GoodsItemsList{
// {"白菜", 1, 100, 100, "30011", 1, "备注:大白菜"},
// {"白菜2", 1, 100, 100, "30012", 1, "备注:大白菜2"},
// // {"白菜3", 1, 100, 100, "1004", 1, "备注:大白菜2"},
// }
// deliveryFee, baseDeliveryFee, err := api.PreCreateByShopFn(&PreCreateOrder{
// PartnerOrderCode: "817102016000041",
// OrderType: 1,
// PositionSource: 3,
// ReceiverAddress: "四川成都",
// ReceiverLongitude: 104.093445,
// ReceiverLatitude: 30.661585,
// GoodsTotalAmountCent: 100,
// GoodsActualAmountCent: 100,
// GoodsWeight: 0.25,
// GoodsCount: 1,
// GoodsItemList: aa,
// //ServiceGoodsId: nil,
// //BaseGoodsId: nil,
// //OutShopCode: "637910",
// ChainStoreID: "209476483",
// })
// fmt.Println(err)
// fmt.Println(deliveryFee)
// fmt.Println(baseDeliveryFee)
//}
//
//func TestDataUnmas(t *testing.T) {
// data := `{"signature":"5a4270c8fb3c4a3a641d2f5f66990c503c7248ecd51248b020e0b44db75a6761","app_id":"6705486294797503379","timestamp":"1648861445686","business_data":"{\"callback_business_type\":\"orderStatusNotify\",\"param\":{\"app_id\":\"6705486294797503379\",\"carrier_driver_name\":\"\",\"carrier_driver_phone\":\"\",\"order_id\":300000388333833530,\"order_status\":1,\"partner_order_code\":\"88386523916938\",\"push_time\":1648861445686,\"transfer\":0}}"}`
// fnNotify := &ShortStatus{}
// if err := json.Unmarshal([]byte(data), fnNotify); err != nil {
// baseapi.SugarLogger.Debugf("FN callback string to ChainstoreStatusNotify failed with err:%v", err)
// }
//
// fmt.Println("data", fnNotify.BusinessData)
// fmt.Println("data", fnNotify.AppId)
// fmt.Println("data", fnNotify.Signature)
//
// retsult := &OrderStatusNottify{}
// err := json.Unmarshal([]byte(fnNotify.BusinessData), retsult)
// fmt.Println("err1======", err)
// fmt.Println("retsult", retsult)
// fmt.Println("retsult", retsult.Param)
// fmt.Println("retsult", retsult.CallbackBusinessType)
// fmt.Println("retsult", retsult.Param.PartnerOrderCode)
//}
//
//func TestDaDa(t *testing.T) {
// fmt.Println("美团", 1&1)
// fmt.Println("达达", 2&1)
// fmt.Println("蜂鸟", 4&1)
//
// fmt.Println("美团", 1&0)
// fmt.Println("达达", 2&0)
// fmt.Println("蜂鸟", 4&0)
//}

141
platformapi/sfps/sfpsapi.go Normal file
View File

@@ -0,0 +1,141 @@
package fnpsapi
import (
"crypto/md5"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"strings"
"sync"
"time"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
//func (a *API) SetToken(token string) {
// a.locker.Lock()
// defer a.locker.Unlock()
// a.accessToken = token
//}
//
//func (a *API) SetRefreshToken(token string) {
// a.locker.Lock()
// defer a.locker.Unlock()
// a.refreshToken = token
//}
//
//func (a *API) MakeFnRequestHead() map[string]interface{} {
// requestParam := make(map[string]interface{}, 6)
// requestParam["access_token"] = a.accessToken
// requestParam["signature"] = a.signature
// requestParam["merchant_id"] = a.merchantId
// requestParam["version"] = a.version
// requestParam["app_id"] = a.appID
// requestParam["timestamp"] = a.timestamp
// return requestParam
//}
func New(devId, devKey string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
// 查询蜂鸟refeshToken
return &API{
devId: devId,
devKey: devKey,
locker: sync.RWMutex{},
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
func (a *API) signParam(params []byte) (sig string) {
sign := fmt.Sprintf("%s&%s&%s", string(params), a.devId, a.devKey)
md2sign := md5.Sum([]byte(sign))
return base64.StdEncoding.EncodeToString(md2sign[:])
}
func (a *API) AccessAPI(baseUrl, actionApi, method string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
bizParams["push_time"] = utils.Int64ToStr(time.Now().Unix())
signParam, err := json.Marshal(bizParams)
if err != nil {
return nil, err
}
//bizParams["sign"] = a.signParam(signParam)
//data, err := json.Marshal(bizParams)
//if err != nil {
// return nil, err
//}
// 全路径请求参数
fullURL := utils.GenerateGetURL(baseUrl, actionApi, map[string]interface{}{"sign": a.signParam(signParam)})
// 发送请求
sendUrl := func() *http.Request {
var request *http.Request
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(signParam)))
request.Header.Set("Content-Type", "application/json")
return request
}
// 数据解析
dataMarshal := func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
if jsonResult1 == nil {
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
}
if err != nil {
return "", err
}
if utils.MustInterface2Int64(jsonResult1["code"]) != 200 {
errLevel = platformapi.ErrLevelGeneralFail
err = utils.NewErrorCode(jsonResult1["msg"].(string), utils.Int64ToStr(utils.MustInterface2Int64(jsonResult1["code"])))
baseapi.SugarLogger.Debugf("sfps AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
}
retVal = jsonResult1
return errLevel, err
}
err = platformapi.AccessPlatformAPIWithRetry(a.client, sendUrl, a.config, dataMarshal)
return retVal, err
}
//
//// 获取access_token
//func (a *API) GetAccessToken() (tokenInfo *TokenInfo, err error) {
// parameter := make(map[string]interface{}, 6)
// parameter["grant_type"] = "refresh_token"
// parameter["app_id"] = a.appID
// parameter["merchant_id"] = a.merchantId
//
// // 先去刷新token,没有的话再去获取token(code只能使用一次,生成的token管一年)
// var result map[string]interface{}
// switch {
// case a.accessToken != "" && a.refreshToken != "":
// parameter["refresh_token"] = a.refreshToken
// result, err = a.AccessAPI(RefreshTokenUrl, "", RequestPost, parameter)
// case a.accessToken == "" && a.refreshToken == "":
// parameter["grant_type"] = "authorization_code"
// parameter["code"] = a.code
// result, err = a.AccessAPI(TokenURL, "", RequestPost, parameter)
// default:
// return nil, errors.New("更换code,请在配置表中删除原蜂鸟token")
// }
// if err != nil {
// return nil, err
// }
// if err := utils.Map2StructByJson(result, &tokenInfo, false); err != nil {
// return nil, err
// }
//
// businessData := &BusinessData{}
// if err := json.Unmarshal([]byte(utils.Interface2String(result["business_data"])), businessData); err != nil {
// return nil, err
// }
// tokenInfo.BusinessDataObj = businessData
// return tokenInfo, err
//}

119
platformapi/sfps/store.go Normal file
View File

@@ -0,0 +1,119 @@
package fnpsapi
//
//import (
// "encoding/json"
// "fmt"
// "strings"
//
// "git.rosy.net.cn/baseapi/utils"
//)
//
//const (
// StoreNotExist = "门店信息不存在"
// StoreExist = "该门店已存在"
//)
//
//const (
// // 创建状态
// ShopCreateStatusAuditRejected = 10 // 上架审核中
// ShopCreateStatusAuditPassed = 20 // 正常(已上架)
// ShopCreateStatusAuditCreated = 30 // 上架审核失败
// ShopCreateStatusAuditOnline = 40 // 已冻结
// ShopCreateStatusAuditUpdateRejected = 50 // 已下架
// // 修改状态
// ShopUpdateStatusAuditRejected = 0 // 无修改
// ShopUpdateStatusAuditPassed = 10 // 资料修改审核中
// ShopUpdateStatusAuditCreated = 20 // 审核通过
// ShopUpdateStatusAuditOnline = 30 // 审核驳回
//)
//
//func (a *API) CreateStore(createStoreParam *CreateStoreBaseInfo) (result1 string, err error) {
// requestHead := a.MakeFnRequestHead()
// storeByte, err := json.Marshal(createStoreParam)
// if err != nil {
// return "", err
// }
// requestHead["business_data"] = string(storeByte)
// result, err := a.AccessAPI(ApiURL, "chainstoreCreate", RequestPost, requestHead)
// if err != nil {
// return "", err
// }
//
// createShop := struct {
// ChainStoreId string `json:"chain_store_id"`
// }{}
// if err := json.Unmarshal([]byte(utils.Interface2String(result["business_data"])), &createShop); err != nil {
// return "", err
// }
// return createShop.ChainStoreId, nil
//}
//
//func (a *API) UpdateStore(updateStore *UpdateStoreParam) (err error) {
// requestHead := a.MakeFnRequestHead()
// storeByte, err := json.Marshal(updateStore)
// if err != nil {
// return err
// }
// requestHead["business_data"] = string(storeByte)
// _, err = a.AccessAPI(ApiURL, "chainstoreUpdate", RequestPost, requestHead)
// return
//}
//
//func (a *API) GetStore(storeID string) (getStoreResult *GetOneStoreRespData, err error) {
// params := GetOneStoreParam{
// BaseInfo: BaseInfo{
// AccessToken: a.accessToken,
// Signature: a.signature,
// MerchantID: a.merchantId,
// Version: a.version,
// AppID: a.appID,
// Timestamp: a.timestamp,
// },
// BusinessData: "",
// }
// // 序列化请求参数
// data, err := json.Marshal(GetOneStore{MerchantID: a.merchantId, OutShopCode: storeID})
// if err != nil {
// return nil, err
// }
// params.BusinessData = string(data)
// paramsMap := utils.Struct2FlatMap(params)
//
// result, err := a.AccessAPI(ApiURL, "chainstoreQuery", RequestPost, paramsMap)
// if err != nil {
// return nil, err
// }
// if result["code"].(string) != "200" {
// return nil, fmt.Errorf("%s", result["msg"])
// }
//
// fnResult := &GetOneStoreRespData{}
// if storeData, ok := result["business_data"]; ok {
// if err := json.Unmarshal([]byte(utils.Interface2String(storeData)), fnResult); err != nil {
// return nil, err
// }
// } else {
// return nil, fmt.Errorf("暂无数据")
// }
//
// return fnResult, err
//}
//
//func IsErrShopNotExist(err error) bool {
// if err != nil {
// if strings.Contains(err.Error(), StoreNotExist) {
// return true
// }
// }
// return false
//}
//
//func IsErrShopExist(err error) bool {
// if err != nil {
// if strings.Contains(err.Error(), StoreExist) {
// return true
// }
// }
// return false
//}

View File

@@ -0,0 +1,73 @@
package tiktok
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
"net/http"
"strings"
)
func (a *API) GetAppID() string {
return a.clientKey
}
func (a *API) GetSecret() string {
return a.clientSecret
}
func New(clientSecret, clientKey string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
clientSecret: clientSecret,
clientKey: clientKey,
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
func (a *API) AccessAPI(baseUrl, actionApi, method string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
// 序列化
data, err := json.Marshal(bizParams)
if err != nil {
return nil, err
}
// 全路径请求参数
fullURL := utils.GenerateGetURL(baseUrl, actionApi, nil)
// 发送请求
sendUrl := func() *http.Request {
var request *http.Request
if http.MethodPost == method {
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(data)))
} else {
request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(baseUrl, actionApi, bizParams), nil)
}
switch actionApi {
case TiktokTokenUrl:
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
case TiktokRefreshTokenUrl:
request.Header.Set("Content-Type", "multipart/form-data")
}
return request
}
// 数据解析
dataMarshal := func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
if jsonResult1 == nil {
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
}
retVal = jsonResult1
return errLevel, err
}
err = platformapi.AccessPlatformAPIWithRetry(a.client, sendUrl, a.config, dataMarshal)
return retVal, err
}

View File

@@ -0,0 +1,24 @@
package tiktok
import (
"git.rosy.net.cn/baseapi/platformapi"
"net/http"
"sync"
)
const (
BaseURL = "https://open.douyin.com"
TiktokTokenUrl = "/oauth/access_token/"
TiktokRefreshTokenUrl = "/oauth/renew_refresh_token/"
)
type API struct {
clientSecret string // 应用唯一标识对应的密钥
clientKey string // 应用唯一标识
client *http.Client
config *platformapi.APIConfig
locker sync.RWMutex
msgToken string
msgKey string
}

View File

@@ -0,0 +1,81 @@
package tiktok
import (
"git.rosy.net.cn/baseapi/utils"
"net/http"
)
// OauthAccessTokenResData access_token
type OauthAccessTokenResData struct {
AccessToken string `json:"access_token"` // 接口调用凭证
UnionId string `json:"union_id"` // 当且仅当该网站应用已获得该用户的userinfo授权时才会出现该字段。
Scope string `json:"scope"` // 用户授权的作用域(Scope),使用逗号(,分隔开放平台几乎几乎每个接口都需要特定的Scope。
ExpiresIn uint64 `json:"expires_in"` // access_token接口调用凭证超时时间单位
OpenId string `json:"open_id"` // 授权用户唯一标识
RefreshToken string `json:"refresh_token"` // 用户刷新access_token
DYError
}
// DYError 错误结构体
type DYError struct {
ErrorCode int64 `json:"error_code,omitempty"` // 错误码
Description string `json:"description,omitempty"` // 错误码描述
}
// OauthAccessTokenRes access_token
type OauthAccessTokenRes struct {
Data OauthAccessTokenResData `json:"data"`
Message string `json:"message"`
}
// 获取抖音token
func (a *API) GetTiktokToken(code string) (*OauthAccessTokenRes, error) {
tokenReq := make(map[string]interface{}, 4)
tokenReq["client_secret"] = a.clientSecret
tokenReq["code"] = code
tokenReq["grant_type"] = "authorization_code"
tokenReq["client_key"] = a.clientKey
result, err := a.AccessAPI(BaseURL, TiktokTokenUrl, http.MethodPost, tokenReq)
if err != nil {
return nil, err
}
oauthAccessToken := &OauthAccessTokenRes{}
if err := utils.Map2StructByJson(result, oauthAccessToken, false); err != nil {
return nil, err
}
return oauthAccessToken, nil
}
// OauthRefreshTokenResData 刷新access_token
type OauthRefreshTokenResData struct {
AccessToken string `json:"access_token"` // 接口调用凭证
Scope string `json:"scope"` // 用户授权的作用域
ExpiresIn uint64 `json:"expires_in"` // 过期时间,单位(秒)
OpenId string `json:"open_id"` // 当前应用下,授权用户唯一标识
RefreshToken string `json:"refresh_token"` // 用户刷新
DYError
}
// OauthRefreshTokenRes 刷新access_token
type OauthRefreshTokenRes struct {
Data OauthRefreshTokenResData `json:"data"`
Message string `json:"message"`
}
// 刷新用户Refresh token
func (a *API) RefreshToken(refreshToken string) (*OauthRefreshTokenRes, error) {
tokenReq := make(map[string]interface{}, 2)
tokenReq["client_key"] = a.clientKey
tokenReq["refresh_token"] = refreshToken
// 通过旧的refresh_token获取新的refresh_token调用后旧refresh_token会失效新refresh_token有30天有效期。最多只能获取5次新的refresh_token5次过后需要用户重新授权。
result, err := a.AccessAPI(BaseURL, TiktokRefreshTokenUrl, http.MethodPost, tokenReq)
if err != nil {
return nil, err
}
oauthRefreshToken := &OauthRefreshTokenRes{}
if err := utils.Map2StructByJson(result, oauthRefreshToken, false); err != nil {
return nil, err
}
return oauthRefreshToken, nil
}