回滚美团外卖

This commit is contained in:
邹宗楠
2022-03-15 19:24:35 +08:00
parent cfbbdc5170
commit ef1222df31
4 changed files with 187 additions and 71 deletions

View File

@@ -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开店
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}