回滚美团外卖
This commit is contained in:
@@ -16,10 +16,27 @@ const (
|
||||
)
|
||||
|
||||
//todo 返回参数没做玩
|
||||
//type TokenInfo struct {
|
||||
// AccessToken string `json:"access_token"`
|
||||
// AppID string `json:"app_id"`
|
||||
// ExpireTime int64 `json:"expire_time"`
|
||||
//}
|
||||
|
||||
// 获取token
|
||||
type TokenInfo struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
AppID string `json:"app_id"`
|
||||
ExpireTime int64 `json:"expire_time"`
|
||||
Sign string `json:"sign"` //返回值签名,详见开放平台侧返回值签名算法
|
||||
Code string `json:"code"` //错误码,详见开放平台侧错误码映射表
|
||||
Msg string `json:"msg"` //错误信息
|
||||
BusinessData string `json:"business_data"` // string
|
||||
}
|
||||
|
||||
type BusinessData struct {
|
||||
AppID string `json:"app_id"` //应用id
|
||||
MerchantID string `json:"merchant_id"` //商户id
|
||||
AccessToken string `json:"access_token"` //凭证token
|
||||
RefreshToken string `json:"refresh_token"` //刷新token
|
||||
ExpireIn string `json:"expire_in"` //access_token剩余有效时间,单位:秒,默认有效期是一年
|
||||
ReExpireIn string `json:"re_expire_in"` //refresh_token剩余有效时间
|
||||
}
|
||||
|
||||
// 注册请求api
|
||||
@@ -32,14 +49,79 @@ type API struct {
|
||||
timestamp int64 `json:"timestamp"`
|
||||
accessToken string `json:"access_token"`
|
||||
appSecret string `json:"app_secret"`
|
||||
|
||||
locker sync.RWMutex
|
||||
client *http.Client
|
||||
config *platformapi.APIConfig
|
||||
version string `json:"version"`
|
||||
locker sync.RWMutex
|
||||
client *http.Client
|
||||
config *platformapi.APIConfig
|
||||
}
|
||||
|
||||
//<------------------------------------------------------------->
|
||||
// 请求基础结构体
|
||||
type BaseInfo struct {
|
||||
AccessToken string `json:"access_token"` //凭证token
|
||||
Signature string `json:"signature"`
|
||||
MerchantID string `json:"merchant_id"` //商户id
|
||||
Version string `json:"version"` // 版本固定1.0
|
||||
AppID string `json:"app_id"` //应用id
|
||||
Timestamp int64 `json:"timestamp"` // 当前时间戳
|
||||
}
|
||||
|
||||
//#region 获取蜂鸟门店信息
|
||||
|
||||
// 获取单个门店查询
|
||||
type GetOneStoreParam struct {
|
||||
BaseInfo
|
||||
BusinessData string `json:"business_data"` // 门店基础数据
|
||||
}
|
||||
|
||||
// 获取单个门店基础参数
|
||||
type GetOneStore struct {
|
||||
MerchantID string `json:"merchant_id"` // 商户id
|
||||
OutShopCode string `json:"out_shop_code"` // 外部门店编码
|
||||
}
|
||||
|
||||
// 获取门店返回值信息
|
||||
type GetStoreResp struct {
|
||||
TokenInfo
|
||||
}
|
||||
|
||||
type GetOneStoreRespData struct {
|
||||
Address string `json:"address"` // 门店地址
|
||||
BranchName string `json:"branch_name"` // 门店分店名
|
||||
CategoryID int `json:"category_id"` // 门店类目
|
||||
ChainStoreID int `json:"chain_store_id"` // 蜂鸟门店id,创建接口返回的id
|
||||
ChainstoreType int `json:"chainstore_type"` // 门店类型 1-正式门店;2-测试门店
|
||||
ChainstoreTypeDesc string `json:"chainstore_type_desc"` // 门店类型描述
|
||||
ContactPhone string `json:"contact_phone"` // 门店联系方式
|
||||
CreditCode string `json:"credit_code"` // 统一社会信用代码
|
||||
Latitude float64 `json:"latitude"` // 门店纬度[0,90]
|
||||
Longitude float64 `json:"longitude"` // 门店经度[0,180]
|
||||
MerchantID int `json:"merchant_id"` // 所属商户id
|
||||
ModifyStatus int `json:"modify_status"` // 0-无修改,10-资料修改审核中,20-审核通过,30-a审核驳回
|
||||
ModifyStatusDesc string `json:"modify_status_desc"` // 门店修改状态描述
|
||||
Name string `json:"name"` // 门店主店名
|
||||
OutShopCode string `json:"out_shop_code"` // 外部门店编码
|
||||
OwnerIDNum string `json:"owner_id_num"` // 门店拥有人身份证号
|
||||
OwnerName string `json:"owner_name"` // 门店拥有人姓名
|
||||
PositionSource int `json:"position_source"` // 经纬度来源 坐标属性(1:腾讯地图, 2:百度地图, 3:高德地图),蜂鸟建议使用高德地图
|
||||
PositionSourceDesc string `json:"position_source_desc"` // 经纬度来源说明
|
||||
SettlementAccountID int `json:"settlement_account_id"` // 门店结算账号id
|
||||
SettlementMode int `json:"settlement_mode"` // 门店结算方式 1:实时结算; 2:账期结算;
|
||||
SettlementModeDesc string `json:"settlement_mode_desc"` // 结算说明?
|
||||
Status int `json:"status"` // 0-上架审核中,20-正常(已上架),30-上架审核失败,40-已冻结,50-已下架
|
||||
StatusDesc string `json:"status_desc"` // 门店认证状态描述
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
// CreateStoreParam 创建门店请求参数
|
||||
type CreateStoreParam struct {
|
||||
BaseInfo
|
||||
BusinessData string `json:"business_data"` // 门店基础数据
|
||||
}
|
||||
|
||||
// 创建门店基础数据
|
||||
type CreateStoreBaseInfo struct {
|
||||
BranchShopName string `json:"branch_shop_name"` // 门店主店名 必填
|
||||
ContactPhone string `json:"contact_phone"` // 门店联系方式
|
||||
OwnerIDPicFrontHash string `json:"owner_id_pic_front_hash"` // 身份证正面
|
||||
@@ -61,3 +143,16 @@ type CreateStoreParam struct {
|
||||
OwnerIDPicBackHash string `json:"owner_id_pic_back_hash"` // 身份证反面
|
||||
PositionSource int `json:"position_source"` // 经纬度来源只支持高德(默认值3)
|
||||
}
|
||||
|
||||
type GetStoreResult struct {
|
||||
ChainStoreCode string `json:"chain_store_code"`
|
||||
ChainStoreName string `json:"chain_store_name"`
|
||||
Address string `json:"address"`
|
||||
Latitude string `json:"latitude"`
|
||||
Longitude string `json:"longitude"`
|
||||
PositionSource int `json:"position_source"`
|
||||
City string `json:"city"`
|
||||
ContactPhone string `json:"contact_phone"`
|
||||
ServiceCode string `json:"service_code"`
|
||||
Status int `json:"status"` //1关店,2开店
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func New(appID, appSecret, merchantId string, config ...*platformapi.APIConfig)
|
||||
func (a *API) signParam2() (sig string) {
|
||||
sb := new(strings.Builder)
|
||||
sb.WriteString("grant_type=")
|
||||
sb.WriteString("CODE") //todo
|
||||
sb.WriteString(a.grantType)
|
||||
sb.WriteString("&code=")
|
||||
sb.WriteString(a.code) //todo
|
||||
sb.WriteString("&app_id=")
|
||||
@@ -104,6 +104,8 @@ func (a *API) AccessAPI(baseUrl, actionApi, method string, bizParams map[string]
|
||||
|
||||
// 获取access_token
|
||||
func (a *API) GetAccessToken() (tokenInfo *TokenInfo, err error) {
|
||||
a.grantType = "authorization_code"
|
||||
a.signature = a.signParam2()
|
||||
result, err := a.AccessAPI(TokenURL, "", RequestPost, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package fnpsapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -19,29 +20,41 @@ func (a *API) CreateStore(createStoreParam *CreateStoreParam) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
type GetStoreResult struct {
|
||||
ChainStoreCode string `json:"chain_store_code"`
|
||||
ChainStoreName string `json:"chain_store_name"`
|
||||
Address string `json:"address"`
|
||||
Latitude string `json:"latitude"`
|
||||
Longitude string `json:"longitude"`
|
||||
PositionSource int `json:"position_source"`
|
||||
City string `json:"city"`
|
||||
ContactPhone string `json:"contact_phone"`
|
||||
ServiceCode string `json:"service_code"`
|
||||
Status int `json:"status"` //1关店,2开店
|
||||
}
|
||||
|
||||
// 获取门店(单个)
|
||||
func (a *API) GetStore(storeID string) (getStoreResult *GetStoreResult, err error) {
|
||||
result, err := a.AccessAPI("v2/chain_store/query", URL, map[string]interface{}{
|
||||
"chain_store_code": []string{storeID},
|
||||
}, true)
|
||||
if err == nil {
|
||||
if data, ok := result["data"].([]interface{}); ok {
|
||||
utils.Map2StructByJson(data[0], &getStoreResult, false)
|
||||
} else {
|
||||
err = fmt.Errorf(result["msg"].(string))
|
||||
}
|
||||
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", RequestGet, paramsMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result["code"] != "200" {
|
||||
return nil, fmt.Errorf("%s", result["msg"])
|
||||
}
|
||||
|
||||
if data, ok := result["business_data"].([]interface{}); ok {
|
||||
utils.Map2StructByJson(data[0], &getStoreResult, false)
|
||||
} else {
|
||||
err = fmt.Errorf(result["msg"].(string))
|
||||
}
|
||||
return getStoreResult, err
|
||||
}
|
||||
@@ -65,7 +78,7 @@ func IsErrShopExist(err error) bool {
|
||||
}
|
||||
|
||||
func (a *API) UpdateStore(createStoreParam *CreateStoreParam) (err error) {
|
||||
params := utils.Struct2FlatMap(createStoreParam)
|
||||
_, err = a.AccessAPI("v2/chain_store/update", URL, params, true)
|
||||
//params := utils.Struct2FlatMap(createStoreParam)
|
||||
//_, err = a.AccessAPI("v2/chain_store/update", URL, params, true)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -91,51 +91,57 @@ func Err2CallbackResponse(err error, data string) *CallbackResponse {
|
||||
}
|
||||
|
||||
func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackResponse *CallbackResponse) {
|
||||
if err := request.ParseForm(); err != nil {
|
||||
baseapi.SugarLogger.Warnf("mtwm GetCallbackMsg ParseForm failed with error:%v", err)
|
||||
callbackResponse = Err2CallbackResponse(err, "")
|
||||
return nil, callbackResponse
|
||||
}
|
||||
err := request.ParseForm()
|
||||
if err == nil {
|
||||
data := utils.URLValues2Map(request.Form)
|
||||
if dataSign, ok := data[signKey]; ok {
|
||||
// fullURL := strings.TrimRight(a.callbackURL+request.URL.Path, "/")
|
||||
// sign := a.signParams(fullURL+"?", data)
|
||||
cmd := strings.Trim(request.URL.EscapedPath(), "/")
|
||||
cmd = cmd[strings.LastIndex(cmd, "/")+1:]
|
||||
// if sign != dataSign.(string) && cmd != MsgTypeStoreStatusChanged {
|
||||
// baseapi.SugarLogger.Debugf("mtwm GetCallbackMsg my sign:%v, data sign:%v", sign, dataSign.(string))
|
||||
// callbackResponse = SignatureIsNotOk
|
||||
// } else {
|
||||
msg = &CallbackMsg{
|
||||
Cmd: cmd,
|
||||
}
|
||||
msg.FormData = make(url.Values)
|
||||
for k, v := range data {
|
||||
// 美团外卖的用户催单信息的timestamp是毫秒(其它的事件是秒),统一归一化为秒
|
||||
if cmd == MsgTypeUserUrgeOrder && k == "timestamp" {
|
||||
intV := utils.Str2Int64(v.(string))
|
||||
if intV > time.Now().Unix()*2 {
|
||||
v = utils.Int64ToStr(intV / 1000)
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
msg.FormData.Set(k, v.(string))
|
||||
}
|
||||
msg.Timestamp = utils.Str2Int64(msg.FormData.Get("timestamp"))
|
||||
msg.Sig = dataSign.(string)
|
||||
msg.AppID = msg.FormData.Get("app_id")
|
||||
|
||||
data := utils.URLValues2Map(request.Form)
|
||||
if dataSign, ok := data[signKey]; ok {
|
||||
cmd := strings.Trim(request.URL.EscapedPath(), "/")
|
||||
cmd = cmd[strings.LastIndex(cmd, "/")+1:]
|
||||
msg = &CallbackMsg{
|
||||
Cmd: cmd,
|
||||
}
|
||||
msg.FormData = make(url.Values)
|
||||
for k, v := range data {
|
||||
// 美团外卖的用户催单信息的timestamp是毫秒(其它的事件是秒),统一归一化为秒
|
||||
if cmd == MsgTypeUserUrgeOrder && k == "timestamp" {
|
||||
intV := utils.Str2Int64(v.(string))
|
||||
if intV > time.Now().Unix()*2 {
|
||||
v = utils.Int64ToStr(intV / 1000)
|
||||
data[k] = v
|
||||
if msg.Cmd == MsgTypeOrderRefund || msg.Cmd == MsgTypeOrderPartialRefund {
|
||||
var refundData *CallbackRefundInfo
|
||||
if err = utils.Map2StructByJson(data, &refundData, true); err == nil {
|
||||
if refundData.Food != "" {
|
||||
utils.UnmarshalUseNumber([]byte(refundData.Food), &refundData.FoodList)
|
||||
}
|
||||
if refundData.Pictures != "" {
|
||||
utils.UnmarshalUseNumber([]byte(refundData.Pictures), &refundData.PictureList)
|
||||
}
|
||||
msg.Data = refundData
|
||||
}
|
||||
}
|
||||
msg.FormData.Set(k, v.(string))
|
||||
}
|
||||
msg.Timestamp = utils.Str2Int64(msg.FormData.Get("timestamp"))
|
||||
msg.Sig = dataSign.(string)
|
||||
msg.AppID = msg.FormData.Get("app_id")
|
||||
|
||||
if msg.Cmd == MsgTypeOrderRefund || msg.Cmd == MsgTypeOrderPartialRefund {
|
||||
var refundData *CallbackRefundInfo
|
||||
if err := utils.Map2StructByJson(data, &refundData, true); err == nil {
|
||||
if refundData.Food != "" {
|
||||
utils.UnmarshalUseNumber([]byte(refundData.Food), &refundData.FoodList)
|
||||
}
|
||||
if refundData.Pictures != "" {
|
||||
utils.UnmarshalUseNumber([]byte(refundData.Pictures), &refundData.PictureList)
|
||||
}
|
||||
msg.Data = refundData
|
||||
}
|
||||
// }
|
||||
} else {
|
||||
callbackResponse = SuccessResponse // 美团外卖PING消息没有sign
|
||||
}
|
||||
} else {
|
||||
callbackResponse = SuccessResponse // 美团外卖PING消息没有sign
|
||||
baseapi.SugarLogger.Warnf("mtwm GetCallbackMsg ParseForm failed with error:%v", err)
|
||||
callbackResponse = Err2CallbackResponse(err, "")
|
||||
}
|
||||
|
||||
return msg, callbackResponse
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user