- big big refactor.
This commit is contained in:
@@ -1,97 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fatih/structs"
|
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AccessPlatformAPIWithRetryParams struct {
|
|
||||||
MaxExceedLimitRetryCount int
|
|
||||||
MaxRecoverableRetryCount int
|
|
||||||
SleepSecondWhenExceedLimit time.Duration
|
|
||||||
Client *http.Client
|
|
||||||
Request *http.Request
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
PAErrorLevelSuccess = "JXC4_SUCCESS"
|
|
||||||
PAErrorLevelExceedLimit = "JXC4_EXCEED_LIMIT"
|
|
||||||
PAErrorLevelRecoverable = "JXC4_RECOVERABLE"
|
|
||||||
PAErrorLevelGeneralFail = "JXC4_GENERAL_FAIL"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrRecoverableErrMaxRetry = errors.New("recoverable error reach max retry count!")
|
|
||||||
ErrLimitReachMaxRetry = errors.New("Reach max retry count!")
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrStrHttpCode = "HTTP Code is not 200"
|
|
||||||
ErrStrBusinessCode = "Business code is not ok"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
CBErrMsgUnescape = "can not unescape data:%v, data:%v"
|
|
||||||
CBErrMsgUnmarshal = "can not unmarshal data:%v, data:%v"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
structs.DefaultTagName = "json"
|
|
||||||
}
|
|
||||||
|
|
||||||
func AccessPlatformAPIWithRetry(params *AccessPlatformAPIWithRetryParams, handleResponse func(response *http.Response) (string, error)) error {
|
|
||||||
exceedLimitRetryCount := 0
|
|
||||||
recoverableErrorRetryCount := 0
|
|
||||||
for {
|
|
||||||
response, err := params.Client.Do(params.Request)
|
|
||||||
if err != nil {
|
|
||||||
baseapi.SugarLogger.Debugf("client.Get return err:%v", err)
|
|
||||||
err, ok := err.(net.Error)
|
|
||||||
recoverableErrorRetryCount++
|
|
||||||
if ok && err.Timeout() && recoverableErrorRetryCount <= params.MaxRecoverableRetryCount {
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
defer response.Body.Close()
|
|
||||||
if response.StatusCode != 200 {
|
|
||||||
baseapi.SugarLogger.Debugf("http code is:%d", response.StatusCode)
|
|
||||||
recoverableErrorRetryCount++
|
|
||||||
if recoverableErrorRetryCount <= params.MaxRecoverableRetryCount {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return utils.NewErrorIntCode(ErrStrHttpCode, response.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
errCode, err := handleResponse(response)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if errCode == PAErrorLevelSuccess {
|
|
||||||
return nil
|
|
||||||
} else if errCode == PAErrorLevelExceedLimit {
|
|
||||||
exceedLimitRetryCount++
|
|
||||||
if exceedLimitRetryCount <= params.MaxExceedLimitRetryCount {
|
|
||||||
time.Sleep(params.SleepSecondWhenExceedLimit)
|
|
||||||
} else {
|
|
||||||
return ErrLimitReachMaxRetry
|
|
||||||
}
|
|
||||||
} else if errCode == PAErrorLevelRecoverable {
|
|
||||||
if recoverableErrorRetryCount <= params.MaxRecoverableRetryCount {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return ErrRecoverableErrMaxRetry
|
|
||||||
} else {
|
|
||||||
return utils.NewErrorCode(ErrStrBusinessCode, errCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
package dadaapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
|
||||||
"git.rosy.net.cn/baseapi/platform/common"
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
dadaSandboxURL = "http://newopen.qa.imdada.cn/"
|
|
||||||
dadaProdURL = "http://newopen.imdada.cn/"
|
|
||||||
signKey = "signature"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
clientTimeout = time.Second * 10
|
|
||||||
sleepSecondWhenLimited = 6 * time.Second
|
|
||||||
maxRetryCountWhenNetworkException = 3
|
|
||||||
maxRetryCountWhenReachLimited = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
DadaCodeException = -1
|
|
||||||
DadaCodeSuccess = 0
|
|
||||||
DadaCodeSignErr = 2003
|
|
||||||
DadaCodeRetryLater = 2012
|
|
||||||
DadaCodeNetworkErr = 2455
|
|
||||||
)
|
|
||||||
|
|
||||||
type DadaAPI struct {
|
|
||||||
appKey string
|
|
||||||
appSecret string
|
|
||||||
sourceId string
|
|
||||||
url string
|
|
||||||
callbackURL string
|
|
||||||
client *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
type DadaResult struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
Code int `json:"code"`
|
|
||||||
Msg string `json:"msg"`
|
|
||||||
Result interface{} `json:"result"`
|
|
||||||
ErrorCode int `json:"errorCode"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DadaCity struct {
|
|
||||||
CityName string `json:"cityName"`
|
|
||||||
CityCode string `json:"cityCode"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CancelReason struct {
|
|
||||||
Id int `json:"id"`
|
|
||||||
Reason string `json:"reason"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDadaAPI(appKey, appSecret, sourceId, callbackURL string, isProd bool) *DadaAPI {
|
|
||||||
api := &DadaAPI{
|
|
||||||
appKey: appKey,
|
|
||||||
appSecret: appSecret,
|
|
||||||
sourceId: sourceId,
|
|
||||||
callbackURL: callbackURL,
|
|
||||||
client: &http.Client{Timeout: clientTimeout},
|
|
||||||
}
|
|
||||||
if isProd {
|
|
||||||
api.url = dadaProdURL
|
|
||||||
} else {
|
|
||||||
api.url = dadaSandboxURL
|
|
||||||
}
|
|
||||||
return api
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DadaAPI) signParams(mapData map[string]interface{}) string {
|
|
||||||
keys := make([]string, 0)
|
|
||||||
for k := range mapData {
|
|
||||||
if k != signKey {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
finalStr := d.appSecret
|
|
||||||
for _, k := range keys {
|
|
||||||
finalStr += k + fmt.Sprint(mapData[k])
|
|
||||||
}
|
|
||||||
|
|
||||||
finalStr += d.appSecret
|
|
||||||
// baseapi.SugarLogger.Debugf("sign str:%v", finalStr)
|
|
||||||
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DadaAPI) AccessDada(action string, params map[string]interface{}) (retVal *DadaResult, err error) {
|
|
||||||
params2 := make(map[string]interface{})
|
|
||||||
|
|
||||||
params2["app_key"] = d.appKey
|
|
||||||
params2["timestamp"] = utils.Int64ToStr(utils.GetCurTimestamp())
|
|
||||||
params2["format"] = "json"
|
|
||||||
params2["v"] = "1.0"
|
|
||||||
params2["source_id"] = d.sourceId
|
|
||||||
if params == nil {
|
|
||||||
params2["body"] = ""
|
|
||||||
} else {
|
|
||||||
params2["body"] = string(utils.MustMarshal(params))
|
|
||||||
}
|
|
||||||
params2[signKey] = d.signParams(params2)
|
|
||||||
params2Bytes := utils.MustMarshal(params2)
|
|
||||||
request, _ := http.NewRequest("POST", d.url+action, bytes.NewReader(params2Bytes))
|
|
||||||
request.Header.Set("Content-Type", "application/json")
|
|
||||||
apiAccess := &common.AccessPlatformAPIWithRetryParams{
|
|
||||||
MaxExceedLimitRetryCount: maxRetryCountWhenReachLimited,
|
|
||||||
MaxRecoverableRetryCount: maxRetryCountWhenNetworkException,
|
|
||||||
SleepSecondWhenExceedLimit: sleepSecondWhenLimited,
|
|
||||||
Client: d.client,
|
|
||||||
Request: request,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result string, err error) {
|
|
||||||
jsonResult1, err := utils.HttpResponse2Json(response)
|
|
||||||
if err != nil {
|
|
||||||
baseapi.SugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
|
||||||
return common.PAErrorLevelGeneralFail, err
|
|
||||||
}
|
|
||||||
code := int(utils.MustInterface2Int64(jsonResult1["code"]))
|
|
||||||
retVal = &DadaResult{
|
|
||||||
Code: code,
|
|
||||||
ErrorCode: code,
|
|
||||||
Msg: jsonResult1["msg"].(string),
|
|
||||||
Status: jsonResult1["status"].(string),
|
|
||||||
}
|
|
||||||
|
|
||||||
if code == DadaCodeSuccess {
|
|
||||||
retVal.Result = jsonResult1["result"]
|
|
||||||
return common.PAErrorLevelSuccess, nil
|
|
||||||
}
|
|
||||||
baseapi.SugarLogger.Debug(jsonResult1)
|
|
||||||
if code == DadaCodeRetryLater || code == DadaCodeNetworkErr {
|
|
||||||
return common.PAErrorLevelRecoverable, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return common.PAErrorLevelGeneralFail, utils.NewErrorIntCode(retVal.Msg, code)
|
|
||||||
})
|
|
||||||
|
|
||||||
return retVal, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DadaAPI) GetCities() (retVal []DadaCity, err error) {
|
|
||||||
result, err := d.AccessDada("api/cityCode/list", nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cites := result.Result.([]interface{})
|
|
||||||
for _, v := range cites {
|
|
||||||
v2 := v.(map[string]interface{})
|
|
||||||
city := DadaCity{
|
|
||||||
CityName: v2["cityName"].(string),
|
|
||||||
CityCode: v2["cityCode"].(string),
|
|
||||||
}
|
|
||||||
retVal = append(retVal, city)
|
|
||||||
}
|
|
||||||
return retVal, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DadaAPI) GetCancelReasons() (retVal []CancelReason, err error) {
|
|
||||||
result, err := d.AccessDada("api/order/cancel/reasons", nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cites := result.Result.([]interface{})
|
|
||||||
for _, v := range cites {
|
|
||||||
v2 := v.(map[string]interface{})
|
|
||||||
reason := CancelReason{
|
|
||||||
Id: int(utils.MustInterface2Int64(v2["id"])),
|
|
||||||
Reason: v2["reason"].(string),
|
|
||||||
}
|
|
||||||
retVal = append(retVal, reason)
|
|
||||||
}
|
|
||||||
return retVal, nil
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package elmapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
|
||||||
"git.rosy.net.cn/baseapi/platform/common"
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
|
||||||
"github.com/fatih/structs"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
OrderValid = 10
|
|
||||||
MerchantValid = 12
|
|
||||||
OrderCanceled = 14
|
|
||||||
MerchantInvalid = 15
|
|
||||||
OrderForceInvalid = 17
|
|
||||||
OrderFinished = 18
|
|
||||||
)
|
|
||||||
|
|
||||||
type ELMCallbackResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ELMCallbackMsg struct {
|
|
||||||
AppId int `json:"appId"`
|
|
||||||
RequestId string `json:"requestId"`
|
|
||||||
Type int `json:"type"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
ShopId int `json:"shopId"`
|
|
||||||
Timestamp int64 `json:"timestamp"`
|
|
||||||
UserId int64 `json:"userId"`
|
|
||||||
Signature string `json:"signature"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
SuccessResponse = &ELMCallbackResponse{"ok"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e *ELMAPI) unmarshalData(data []byte, msg interface{}) (callbackResponse *ELMCallbackResponse) {
|
|
||||||
err := utils.UnmarshalUseNumber(data, msg)
|
|
||||||
if err != nil {
|
|
||||||
return &ELMCallbackResponse{
|
|
||||||
Message: fmt.Sprintf(common.CBErrMsgUnmarshal, data, err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ELMAPI) CheckCallbackValidation(mapData map[string]interface{}) (callbackResponse *ELMCallbackResponse) {
|
|
||||||
sign := e.signParamsMap(mapData, "")
|
|
||||||
if remoteSign, _ := mapData[signKey].(string); sign != remoteSign {
|
|
||||||
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, remoteSign)
|
|
||||||
return &ELMCallbackResponse{Message: "signature is invalid"}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ELMAPI) GetCallbackMsg(data []byte) (msg *ELMCallbackMsg, callbackResponse *ELMCallbackResponse) {
|
|
||||||
msg = new(ELMCallbackMsg)
|
|
||||||
if callbackResponse = e.unmarshalData(data, msg); callbackResponse != nil {
|
|
||||||
return nil, callbackResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
mapData := structs.Map(msg)
|
|
||||||
callbackResponse = e.CheckCallbackValidation(mapData)
|
|
||||||
return msg, callbackResponse
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
package elmapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
|
||||||
"git.rosy.net.cn/baseapi/platform/common"
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
clientTimeout = time.Second * 10
|
|
||||||
sleepSecondWhenLimited = 6 * time.Second
|
|
||||||
maxRetryCountWhenNetworkException = 3
|
|
||||||
maxRetryCountWhenReachLimited = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ELM_API_URL_SANDBOX = "https://open-api-sandbox.shop.ele.me/api/v1/"
|
|
||||||
ELM_API_URL_PROD = "https://open-api.shop.ele.me/api/v1/"
|
|
||||||
signKey = "signature"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ELMResult struct {
|
|
||||||
Id string
|
|
||||||
Result interface{}
|
|
||||||
Error map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ELMAPI struct {
|
|
||||||
token string
|
|
||||||
appKey string
|
|
||||||
secret string
|
|
||||||
url *url.URL
|
|
||||||
client *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
type ELMPayload struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
Nop string `json:"nop"`
|
|
||||||
Metas map[string]interface{} `json:"metas"`
|
|
||||||
Params map[string]interface{} `json:"params"`
|
|
||||||
Action string `json:"action"`
|
|
||||||
Id string `json:"id"`
|
|
||||||
Signature string `json:"signature"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewELMAPI(token, appKey, secret string, isProd bool) *ELMAPI {
|
|
||||||
api := &ELMAPI{
|
|
||||||
token: token,
|
|
||||||
appKey: appKey,
|
|
||||||
secret: secret,
|
|
||||||
client: &http.Client{Timeout: clientTimeout},
|
|
||||||
}
|
|
||||||
|
|
||||||
if isProd {
|
|
||||||
api.url, _ = url.Parse(ELM_API_URL_PROD)
|
|
||||||
} else {
|
|
||||||
api.url, _ = url.Parse(ELM_API_URL_SANDBOX)
|
|
||||||
}
|
|
||||||
return api
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ELMAPI) signParamsMap(mapData map[string]interface{}, prefix string) string {
|
|
||||||
keyValues := make([]string, 0)
|
|
||||||
for k, v := range mapData {
|
|
||||||
if k != signKey {
|
|
||||||
vStr := ""
|
|
||||||
if prefix == "" { // callback sign
|
|
||||||
vStr = fmt.Sprint(v)
|
|
||||||
} else { // call sign
|
|
||||||
vBytes := utils.MustMarshal(v)
|
|
||||||
vStr = string(vBytes)
|
|
||||||
}
|
|
||||||
keyValues = append(keyValues, k+"="+vStr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Strings(keyValues)
|
|
||||||
finalStr := prefix + strings.Join(keyValues, "") + e.secret
|
|
||||||
// baseapi.SugarLogger.Debugf("sign str:%v", finalStr)
|
|
||||||
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ELMAPI) signParams(action string, payload *ELMPayload) string {
|
|
||||||
mapData := utils.MergeMaps(payload.Metas, payload.Params)
|
|
||||||
return e.signParamsMap(mapData, action+e.token)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ELMAPI) AccessELM(action string, params map[string]interface{}) (retVal *ELMResult, err error) {
|
|
||||||
if params == nil {
|
|
||||||
params = make(map[string]interface{}, 0)
|
|
||||||
}
|
|
||||||
metas := map[string]interface{}{
|
|
||||||
"app_key": e.appKey,
|
|
||||||
"timestamp": utils.GetCurTimestamp(),
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := &ELMPayload{
|
|
||||||
Token: e.token,
|
|
||||||
Nop: "1.0.0",
|
|
||||||
Metas: metas,
|
|
||||||
Params: params,
|
|
||||||
Action: action,
|
|
||||||
Id: utils.GetUUID(),
|
|
||||||
}
|
|
||||||
|
|
||||||
payload.Signature = e.signParams(action, payload)
|
|
||||||
|
|
||||||
apiAccess := &common.AccessPlatformAPIWithRetryParams{
|
|
||||||
MaxExceedLimitRetryCount: maxRetryCountWhenReachLimited,
|
|
||||||
MaxRecoverableRetryCount: maxRetryCountWhenNetworkException,
|
|
||||||
SleepSecondWhenExceedLimit: sleepSecondWhenLimited,
|
|
||||||
Client: e.client,
|
|
||||||
Request: &http.Request{
|
|
||||||
Method: "POST",
|
|
||||||
URL: e.url,
|
|
||||||
Header: http.Header{
|
|
||||||
"Content-Type": []string{"application/json; charset=utf-8"},
|
|
||||||
"Content-Encoding": []string{"gzip, deflate"},
|
|
||||||
"User-Agent": []string{"eleme-golang-api"},
|
|
||||||
// "x-eleme-requestid": []string{payload.Id},
|
|
||||||
},
|
|
||||||
|
|
||||||
Body: ioutil.NopCloser(strings.NewReader(string(utils.MustMarshal(payload)))),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result string, err error) {
|
|
||||||
jsonResult1, err := utils.HttpResponse2Json(response)
|
|
||||||
if err != nil {
|
|
||||||
baseapi.SugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
|
||||||
return common.PAErrorLevelGeneralFail, err
|
|
||||||
}
|
|
||||||
resultError, _ := jsonResult1["error"].(map[string]interface{})
|
|
||||||
retVal = &ELMResult{
|
|
||||||
Id: jsonResult1["id"].(string),
|
|
||||||
Error: resultError,
|
|
||||||
Result: jsonResult1["result"],
|
|
||||||
}
|
|
||||||
errinfoMap := retVal.Error
|
|
||||||
if errinfoMap == nil {
|
|
||||||
return common.PAErrorLevelSuccess, nil
|
|
||||||
}
|
|
||||||
baseapi.SugarLogger.Debug(jsonResult1)
|
|
||||||
errCode := errinfoMap["code"].(string)
|
|
||||||
if errCode == "EXCEED_LIMIT" {
|
|
||||||
return common.PAErrorLevelExceedLimit, nil
|
|
||||||
} else if errCode == "SERVER_ERROR" || errCode == "BIZ_SYSTEM_ERROR" || errCode == "BIZ_1006" || errCode == "BUSINESS_ERROR" {
|
|
||||||
return common.PAErrorLevelRecoverable, nil
|
|
||||||
} else {
|
|
||||||
return common.PAErrorLevelGeneralFail, utils.NewErrorCode(errinfoMap["message"].(string), errCode)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return retVal, err
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package elmapi
|
|
||||||
|
|
||||||
const (
|
|
||||||
ELMOrderStatusPending = "pending"
|
|
||||||
ELMOrderStatusUnprocessed = "unprocessed"
|
|
||||||
ELMOrderStatusRefunding = "refunding"
|
|
||||||
ELMOrderStatusValid = "valid"
|
|
||||||
ELMOrderStatusInvalid = "invalid"
|
|
||||||
ELMOrderStatusSettled = "settled"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e *ELMAPI) GetOrder(orderId string) (map[string]interface{}, error) {
|
|
||||||
result, err := e.AccessELM("eleme.order.getOrder", map[string]interface{}{
|
|
||||||
"orderId": orderId,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
innerResult := result.Result.(map[string]interface{})
|
|
||||||
return innerResult, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
package jdapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
|
||||||
"git.rosy.net.cn/baseapi/platform/common"
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JDCallbackResponse struct {
|
|
||||||
Code string `json:"code"`
|
|
||||||
Msg string `json:"msg"`
|
|
||||||
Data string `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type JDOrderMsg struct {
|
|
||||||
Id int `json:"-"` // 用于传递Jdorder的主键值,减少一次读库操作
|
|
||||||
BillId string `json:"billId"`
|
|
||||||
StatusId string `json:"statusId"`
|
|
||||||
Timestamp string `json:"timestamp"`
|
|
||||||
Remark string `json:"remark"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type JDDeliveryStatusMsg struct {
|
|
||||||
OrderId string
|
|
||||||
DeliveryStatusTime string
|
|
||||||
DeliveryManNo string
|
|
||||||
DeliveryManName string
|
|
||||||
DeliveryManPhone string
|
|
||||||
DeliveryCarrierNo string
|
|
||||||
DeliveryCarrierName string
|
|
||||||
DeliveryStatus int
|
|
||||||
Remark string
|
|
||||||
FailType string
|
|
||||||
CreatePin string
|
|
||||||
OpTime int64
|
|
||||||
InputTime string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
SuccessResponse = &JDCallbackResponse{Code: "0", Msg: "success", Data: ""}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (j *JDAPI) unmarshalData(strData string, msg interface{}) (callbackResponse *JDCallbackResponse) {
|
|
||||||
err := utils.UnmarshalUseNumber([]byte(strData), msg)
|
|
||||||
if err != nil {
|
|
||||||
return &JDCallbackResponse{
|
|
||||||
Code: JDerrorCodeAbnormalParam,
|
|
||||||
Msg: fmt.Sprintf(common.CBErrMsgUnmarshal, strData, err),
|
|
||||||
Data: strData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JDAPI) CheckCallbackValidation(request *http.Request) (callbackResponse *JDCallbackResponse) {
|
|
||||||
mapData := make(map[string]interface{})
|
|
||||||
mapData["token"] = request.FormValue("token")
|
|
||||||
mapData["app_key"] = request.FormValue("app_key")
|
|
||||||
mapData["timestamp"] = request.FormValue("timestamp")
|
|
||||||
mapData["format"] = request.FormValue("format")
|
|
||||||
mapData["app_secret"] = j.appSecret
|
|
||||||
mapData["v"] = request.FormValue("v")
|
|
||||||
mapData[JD_PARAM_JSON] = request.FormValue(JD_PARAM_JSON)
|
|
||||||
|
|
||||||
sign := j.signParams(mapData)
|
|
||||||
if sign != request.FormValue(signKey) {
|
|
||||||
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, request.FormValue(signKey))
|
|
||||||
return &JDCallbackResponse{
|
|
||||||
Code: JDerrorCodeInvalidSign,
|
|
||||||
Msg: "signature is invalid",
|
|
||||||
Data: string(utils.MustMarshal(mapData)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JDAPI) getCommonOrderCallbackMsg(request *http.Request, msg interface{}, needDecode bool) (callbackResponse *JDCallbackResponse) {
|
|
||||||
if callbackResponse = j.CheckCallbackValidation(request); callbackResponse != nil {
|
|
||||||
return callbackResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
jdParamJSON := request.FormValue(JD_PARAM_JSON)
|
|
||||||
if needDecode {
|
|
||||||
if jdParamJSON2, err := url.QueryUnescape(jdParamJSON); err == nil {
|
|
||||||
jdParamJSON = jdParamJSON2
|
|
||||||
} else {
|
|
||||||
return &JDCallbackResponse{
|
|
||||||
Code: JDerrorCodeAbnormalParam,
|
|
||||||
Msg: fmt.Sprintf(common.CBErrMsgUnescape, jdParamJSON, err),
|
|
||||||
Data: jdParamJSON,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if callbackResponse = j.unmarshalData(jdParamJSON, msg); callbackResponse != nil {
|
|
||||||
return callbackResponse
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JDAPI) GetOrderCallbackMsg(request *http.Request) (msg *JDOrderMsg, callbackResponse *JDCallbackResponse) {
|
|
||||||
msg = new(JDOrderMsg)
|
|
||||||
callbackResponse = j.getCommonOrderCallbackMsg(request, msg, false)
|
|
||||||
return msg, callbackResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JDAPI) GetOrderApplyCancelCallbackMsg(request *http.Request) (msg *JDOrderMsg, callbackResponse *JDCallbackResponse) {
|
|
||||||
msg = new(JDOrderMsg)
|
|
||||||
callbackResponse = j.getCommonOrderCallbackMsg(request, msg, true)
|
|
||||||
return msg, callbackResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JDAPI) GetOrderDeliveryCallbackMsg(request *http.Request) (msg *JDDeliveryStatusMsg, callbackResponse *JDCallbackResponse) {
|
|
||||||
msg = new(JDDeliveryStatusMsg)
|
|
||||||
callbackResponse = j.getCommonOrderCallbackMsg(request, msg, true)
|
|
||||||
return msg, callbackResponse
|
|
||||||
}
|
|
||||||
@@ -1,347 +0,0 @@
|
|||||||
package jdapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/md5"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
|
||||||
"git.rosy.net.cn/baseapi/platform/common"
|
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
clientTimeout = time.Second * 10
|
|
||||||
sleepSecondWhenLimited = 6 * time.Second
|
|
||||||
maxRetryCountWhenNetworkException = 3
|
|
||||||
maxRetryCountWhenReachLimited = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
JD_PARAM_JSON = "jd_param_json"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// JDErrorCodeSuccess 操作成功
|
|
||||||
JDErrorCodeSuccess = "0"
|
|
||||||
// JDerrorCodeAccessFailed 操作失败,请重试,如还不能正常提供服务,可以提交工单(https://opengd.jd.com)详细说明一下,开放平台跟进回复。
|
|
||||||
JDerrorCodeAccessFailed = "-1"
|
|
||||||
// JDerrorCodeFailedCanAutoRetry 操作失败,系统会自动重试,如还不能正常提供服务,可以提交工单(https://opengd.jd.com)详细说明一下,开放平台跟进回复。
|
|
||||||
JDerrorCodeFailedCanAutoRetry = "-10000"
|
|
||||||
JDerrorCodeFailedAccessDB = "10000"
|
|
||||||
// JDerrorCodeMissingMandatoryParam 请求参数中缺失必填项信息,请检查,如不清楚,请访问到家开放平台(https://opendj.jd.com)API分组有接口详细说明。
|
|
||||||
JDerrorCodeMissingMandatoryParam = "10005"
|
|
||||||
JDerrorCodeInvalidToken = "10013"
|
|
||||||
JDerrorCodeInvalidSign = "10014"
|
|
||||||
JDerrorCodeAbnormalParam = "10015"
|
|
||||||
JDerrorCodeMethodNotExist = "10018"
|
|
||||||
JDErrorCodeExceedLimit = "10032"
|
|
||||||
|
|
||||||
JDErrorCodeTimeout = "100022"
|
|
||||||
JDErrorCodeTomcateFailed = "100023"
|
|
||||||
JDErrorCodeLoadUnexpected = "100024"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
jdAPIURL = "https://openo2o.jd.com/djapi/%s"
|
|
||||||
signKey = "sign"
|
|
||||||
AllPage = 0
|
|
||||||
DefaultPageSize = 50
|
|
||||||
)
|
|
||||||
|
|
||||||
type JDAPI struct {
|
|
||||||
token string
|
|
||||||
appKey string
|
|
||||||
appSecret string
|
|
||||||
client *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrStrInnerCodeIsNotOk = "JD result inner code is not ok"
|
|
||||||
|
|
||||||
exceedLimitCodes = map[string]int{
|
|
||||||
JDErrorCodeExceedLimit: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo replace all magic number
|
|
||||||
canRetryCodes = map[string]int{
|
|
||||||
JDerrorCodeFailedCanAutoRetry: 1,
|
|
||||||
JDerrorCodeAccessFailed: 1,
|
|
||||||
JDerrorCodeFailedAccessDB: 1,
|
|
||||||
JDErrorCodeTimeout: 1,
|
|
||||||
JDErrorCodeTomcateFailed: 1,
|
|
||||||
JDErrorCodeLoadUnexpected: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
jdResultInnerCodeKeys = []string{"code", "retCode", "errorCode"}
|
|
||||||
|
|
||||||
jdResultInnerCodeOK = map[string]int{
|
|
||||||
"None": 1,
|
|
||||||
"0": 1,
|
|
||||||
"1": 1,
|
|
||||||
"200": 1,
|
|
||||||
"190005": 1, // 部分失败
|
|
||||||
}
|
|
||||||
|
|
||||||
jdResultNoPageInnerDataKeys = []string{"result", "data"}
|
|
||||||
jdResultPageInner2DataKeys = []string{"result", "resultList"}
|
|
||||||
jdResultPageTotalCountKeys = []string{"totalCount", "count"}
|
|
||||||
)
|
|
||||||
|
|
||||||
type PageResultParser func(map[string]interface{}, int) ([]interface{}, int)
|
|
||||||
|
|
||||||
func (j *JDAPI) signParams(jdParams map[string]interface{}) string {
|
|
||||||
var keys []string
|
|
||||||
for k := range jdParams {
|
|
||||||
if k != "app_secret" && k != signKey {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Strings(keys)
|
|
||||||
secretStr := fmt.Sprint(jdParams["app_secret"])
|
|
||||||
allStr := secretStr
|
|
||||||
for _, k := range keys {
|
|
||||||
allStr += k + fmt.Sprint(jdParams[k])
|
|
||||||
}
|
|
||||||
allStr = allStr + secretStr
|
|
||||||
|
|
||||||
return fmt.Sprintf("%X", md5.Sum([]byte(allStr)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func genGetURL(baseURL, apiStr string, params map[string]interface{}) string {
|
|
||||||
fullURL := ""
|
|
||||||
|
|
||||||
if params != nil {
|
|
||||||
for k, v := range params {
|
|
||||||
if fullURL == "" {
|
|
||||||
fullURL = "?"
|
|
||||||
} else {
|
|
||||||
fullURL += "&"
|
|
||||||
}
|
|
||||||
fullURL += k + "=" + url.QueryEscape(fmt.Sprint(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(baseURL, apiStr) + fullURL
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewJDAPI(token, appKey, appSecret string) *JDAPI {
|
|
||||||
return &JDAPI{token, appKey, appSecret, &http.Client{Timeout: clientTimeout}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JDAPI) AccessJDQuery(apiStr string, jdParams map[string]interface{}) (retVal map[string]interface{}, err error) {
|
|
||||||
params := make(map[string]interface{})
|
|
||||||
params["v"] = "1.0"
|
|
||||||
params["format"] = "json"
|
|
||||||
params["app_key"] = j.appKey
|
|
||||||
params["app_secret"] = j.appSecret
|
|
||||||
params["token"] = j.token
|
|
||||||
|
|
||||||
if jdParams == nil {
|
|
||||||
jdParams = make(map[string]interface{}, 0)
|
|
||||||
}
|
|
||||||
jdParamStr, err := json.Marshal(jdParams)
|
|
||||||
if err != nil {
|
|
||||||
baseapi.SugarLogger.Errorf("Error when marshal %v, error:%v", jdParams, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
params["jd_param_json"] = string(jdParamStr)
|
|
||||||
params["timestamp"] = utils.GetCurTimeStr()
|
|
||||||
sign := j.signParams(params)
|
|
||||||
params[signKey] = sign
|
|
||||||
|
|
||||||
url, _ := url.Parse(genGetURL(jdAPIURL, apiStr, params))
|
|
||||||
|
|
||||||
apiAccess := &common.AccessPlatformAPIWithRetryParams{
|
|
||||||
MaxExceedLimitRetryCount: maxRetryCountWhenReachLimited,
|
|
||||||
MaxRecoverableRetryCount: maxRetryCountWhenNetworkException,
|
|
||||||
SleepSecondWhenExceedLimit: sleepSecondWhenLimited,
|
|
||||||
Client: j.client,
|
|
||||||
Request: &http.Request{
|
|
||||||
Method: "GET",
|
|
||||||
URL: url,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (errLevel string, err error) {
|
|
||||||
jsonResult1, err := utils.HttpResponse2Json(response)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
baseapi.SugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
|
||||||
return common.PAErrorLevelGeneralFail, err
|
|
||||||
}
|
|
||||||
|
|
||||||
code := jsonResult1["code"].(string)
|
|
||||||
if code == JDErrorCodeSuccess {
|
|
||||||
retVal = jsonResult1
|
|
||||||
return common.PAErrorLevelSuccess, nil
|
|
||||||
}
|
|
||||||
baseapi.SugarLogger.Debug(jsonResult1)
|
|
||||||
if _, ok := exceedLimitCodes[code]; ok {
|
|
||||||
return common.PAErrorLevelExceedLimit, nil
|
|
||||||
} else if _, ok := canRetryCodes[code]; ok {
|
|
||||||
return common.PAErrorLevelRecoverable, nil
|
|
||||||
} else {
|
|
||||||
return common.PAErrorLevelGeneralFail, utils.NewErrorCode(jsonResult1["msg"].(string), code)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
return retVal, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JDAPI) AccessJDQueryNoPage(apiStr string, jdParams map[string]interface{}, keyToRemove, keyToKeep []string) (interface{}, error) {
|
|
||||||
jsonResult, err := j.AccessJDQuery(apiStr, jdParams)
|
|
||||||
if err != nil {
|
|
||||||
return jsonResult, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var data map[string]interface{}
|
|
||||||
err = utils.UnmarshalUseNumber([]byte(jsonResult["data"].(string)), &data)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return jsonResult, err
|
|
||||||
}
|
|
||||||
|
|
||||||
innerCode := ""
|
|
||||||
for _, innerCodeKey := range jdResultInnerCodeKeys {
|
|
||||||
if innerCode2, ok := data[innerCodeKey]; ok {
|
|
||||||
innerCode = forceInnerCode2Str(innerCode2)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := jdResultInnerCodeOK[innerCode]; ok {
|
|
||||||
for _, innerDataKey := range jdResultNoPageInnerDataKeys {
|
|
||||||
if innerData, ok := data[innerDataKey]; ok {
|
|
||||||
return utils.DictKeysMan(innerData, keyToRemove, keyToKeep), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic("Can not find inner data")
|
|
||||||
} else {
|
|
||||||
return jsonResult, utils.NewErrorCode(ErrStrInnerCodeIsNotOk, innerCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NormalJDQueryHavePageResultParser(data map[string]interface{}, totalCount int) ([]interface{}, int) {
|
|
||||||
var result map[string]interface{}
|
|
||||||
var retVal []interface{}
|
|
||||||
|
|
||||||
tempResult := data["result"]
|
|
||||||
if resultStr, ok := tempResult.(string); ok {
|
|
||||||
if err := utils.UnmarshalUseNumber([]byte(resultStr), &tempResult); err != nil {
|
|
||||||
panic("Wrong format")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = tempResult.(map[string]interface{})
|
|
||||||
|
|
||||||
if totalCount == 0 {
|
|
||||||
for _, totalCountKey := range jdResultPageTotalCountKeys {
|
|
||||||
if totalCount2, ok := result[totalCountKey]; ok {
|
|
||||||
totalCountInt64, _ := totalCount2.(json.Number).Int64()
|
|
||||||
totalCount = int(totalCountInt64)
|
|
||||||
if totalCount == 0 {
|
|
||||||
return make([]interface{}, 0), 0
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if totalCount == 0 {
|
|
||||||
panic("can not find totalCount key")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, inner2ResultKey := range jdResultPageInner2DataKeys {
|
|
||||||
if inner2Result, ok := result[inner2ResultKey]; ok {
|
|
||||||
|
|
||||||
if inner2ResultStr, ok := inner2Result.(string); ok {
|
|
||||||
err := utils.UnmarshalUseNumber([]byte(inner2ResultStr), &retVal)
|
|
||||||
if err != nil {
|
|
||||||
panic("can not unmarshal inner2result")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
retVal = inner2Result.([]interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal, totalCount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("wrong format")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JDAPI) AccessJDQueryHavePage(apiStr string, jdParams map[string]interface{}, keyToRemove, keyToKeep []string, pageResultParser PageResultParser) ([]interface{}, error) {
|
|
||||||
if pageResultParser == nil {
|
|
||||||
pageResultParser = NormalJDQueryHavePageResultParser
|
|
||||||
}
|
|
||||||
|
|
||||||
localJdParams := make(map[string]interface{})
|
|
||||||
if jdParams != nil && len(jdParams) > 0 {
|
|
||||||
for k, v := range jdParams {
|
|
||||||
localJdParams[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalCount := 0
|
|
||||||
pageNo := AllPage
|
|
||||||
pageSize := DefaultPageSize
|
|
||||||
if tempPageNo, ok := localJdParams["pageNo"]; ok {
|
|
||||||
pageNo = tempPageNo.(int)
|
|
||||||
}
|
|
||||||
if tempPageSize, ok := localJdParams["pageSize"]; ok {
|
|
||||||
pageSize = tempPageSize.(int)
|
|
||||||
}
|
|
||||||
|
|
||||||
curPage := pageNo
|
|
||||||
if curPage == AllPage {
|
|
||||||
curPage = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
retVal := make([]interface{}, 0)
|
|
||||||
for {
|
|
||||||
localJdParams["pageNo"] = curPage
|
|
||||||
localJdParams["pageSize"] = pageSize
|
|
||||||
jsonResult, err := j.AccessJDQuery(apiStr, localJdParams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var data map[string]interface{}
|
|
||||||
err = utils.UnmarshalUseNumber([]byte(jsonResult["data"].(string)), &data)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
innerCode := forceInnerCode2Str(data["code"])
|
|
||||||
if innerCode != "0" && innerCode != "200" {
|
|
||||||
return nil, utils.NewErrorCode(ErrStrInnerCodeIsNotOk, innerCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
inResult, totalCount2 := pageResultParser(data, totalCount)
|
|
||||||
totalCount = totalCount2
|
|
||||||
|
|
||||||
inResult = utils.DictKeysMan(inResult, keyToRemove, keyToKeep).([]interface{})
|
|
||||||
retVal = append(retVal, inResult...)
|
|
||||||
|
|
||||||
if curPage == pageNo || curPage*pageSize >= totalCount {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
curPage++
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func forceInnerCode2Str(innerCode interface{}) string {
|
|
||||||
if innerCodeStr, ok := innerCode.(string); ok {
|
|
||||||
return innerCodeStr
|
|
||||||
}
|
|
||||||
return utils.Int64ToStr(utils.MustInterface2Int64(innerCode))
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package jdapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
JdOrderStatusNew = "32000"
|
|
||||||
JdOrderStatusAdjust = "33080"
|
|
||||||
JdOrderStatusUserCancel = "20030"
|
|
||||||
JdOrderStatusWaitOutStore = "32001"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (j JDAPI) OrderQuery(jdParams map[string]interface{}) (retVal []interface{}, err error) {
|
|
||||||
retVal, err = j.AccessJDQueryHavePage("order/es/query", jdParams, nil, nil, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j JDAPI) QuerySingleOrder(orderId string) ([]interface{}, error) {
|
|
||||||
jdParams := make(map[string]interface{})
|
|
||||||
jdParams["orderId"] = orderId
|
|
||||||
return j.AccessJDQueryHavePage("order/es/query", jdParams, nil, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j JDAPI) LegacyQuerySingleOrder(orderId string) (map[string]interface{}, error) {
|
|
||||||
jdParams := make(map[string]interface{})
|
|
||||||
jdParams["orderId"] = orderId
|
|
||||||
|
|
||||||
result, err := j.AccessJDQuery("order/es/query", jdParams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dataStr, _ := result["data"].(string)
|
|
||||||
var data map[string]interface{}
|
|
||||||
utils.UnmarshalUseNumber([]byte(dataStr), &data)
|
|
||||||
result["data"] = data
|
|
||||||
|
|
||||||
var dataResult map[string]interface{}
|
|
||||||
utils.UnmarshalUseNumber([]byte(data["result"].(string)), &dataResult)
|
|
||||||
data["result"] = dataResult
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j JDAPI) OrderAcceptOperate(orderId string, isAgreed bool) (interface{}, error) {
|
|
||||||
jdParams := map[string]interface{}{
|
|
||||||
"orderId": orderId,
|
|
||||||
"isAgreed": utils.Bool2String(isAgreed),
|
|
||||||
"operator": utils.GetAPIOperator(),
|
|
||||||
}
|
|
||||||
return j.AccessJDQueryNoPage("ocs/orderAcceptOperate", jdParams, nil, nil)
|
|
||||||
}
|
|
||||||
@@ -13,34 +13,34 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DadaResponseHttpCodeSuccess = 200
|
ResponseHttpCodeSuccess = 200
|
||||||
DadaResponseHttpCodeGeneralErr = 555
|
ResponseHttpCodeGeneralErr = 555
|
||||||
)
|
)
|
||||||
|
|
||||||
type DadaCallbackMsg struct {
|
type CallbackMsg struct {
|
||||||
ClientId string `json:"client_id"`
|
ClientID string `json:"client_id"`
|
||||||
OrderId string `json:"order_id"`
|
OrderID string `json:"order_id"`
|
||||||
OrderStatus int `json:"order_status"`
|
OrderStatus int `json:"order_status"`
|
||||||
CancelReason string `json:"cancel_reason"`
|
CancelReason string `json:"cancel_reason"`
|
||||||
CancelFrom int `json:"cancel_from"`
|
CancelFrom int `json:"cancel_from"`
|
||||||
UpdateTime int `json:"update_time"`
|
UpdateTime int `json:"update_time"`
|
||||||
Signature string `json:"signature"`
|
Signature string `json:"signature"`
|
||||||
DmId int `json:"dm_id"`
|
DmID int `json:"dm_id"`
|
||||||
DmName string `json:"dm_name"`
|
DmName string `json:"dm_name"`
|
||||||
DmMobile string `json:"dm_mobile"`
|
DmMobile string `json:"dm_mobile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DadaCallbackResponse struct {
|
type CallbackResponse struct {
|
||||||
Code int
|
Code int
|
||||||
Dummy string `json:"dummy"`
|
Dummy string `json:"dummy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
SuccessResponse = &DadaCallbackResponse{Code: DadaResponseHttpCodeSuccess}
|
SuccessResponse = &CallbackResponse{Code: ResponseHttpCodeSuccess}
|
||||||
FailedResponse = &DadaCallbackResponse{Code: DadaResponseHttpCodeGeneralErr}
|
FailedResponse = &CallbackResponse{Code: ResponseHttpCodeGeneralErr}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *DadaAPI) signParamsCallback(mapData map[string]interface{}) string {
|
func (a *API) signCallbackParams(mapData map[string]interface{}) string {
|
||||||
values := make([]string, 0)
|
values := make([]string, 0)
|
||||||
for _, k := range []string{"client_id", "order_id", "update_time"} {
|
for _, k := range []string{"client_id", "order_id", "update_time"} {
|
||||||
values = append(values, fmt.Sprint(mapData[k]))
|
values = append(values, fmt.Sprint(mapData[k]))
|
||||||
@@ -52,7 +52,7 @@ func (d *DadaAPI) signParamsCallback(mapData map[string]interface{}) string {
|
|||||||
return fmt.Sprintf("%x", md5.Sum([]byte(finalStr)))
|
return fmt.Sprintf("%x", md5.Sum([]byte(finalStr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) unmarshalData(data []byte, msg interface{}) (callbackResponse *DadaCallbackResponse) {
|
func (a *API) unmarshalData(data []byte, msg interface{}) (callbackResponse *CallbackResponse) {
|
||||||
err := utils.UnmarshalUseNumber(data, msg)
|
err := utils.UnmarshalUseNumber(data, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FailedResponse
|
return FailedResponse
|
||||||
@@ -60,8 +60,8 @@ func (d *DadaAPI) unmarshalData(data []byte, msg interface{}) (callbackResponse
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) CheckCallbackValidation(mapData map[string]interface{}) (callbackResponse *DadaCallbackResponse) {
|
func (a *API) CheckCallbackValidation(mapData map[string]interface{}) (callbackResponse *CallbackResponse) {
|
||||||
sign := d.signParamsCallback(mapData)
|
sign := a.signCallbackParams(mapData)
|
||||||
if remoteSign, _ := mapData[signKey].(string); sign != remoteSign {
|
if remoteSign, _ := mapData[signKey].(string); sign != remoteSign {
|
||||||
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, remoteSign)
|
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, remoteSign)
|
||||||
return FailedResponse
|
return FailedResponse
|
||||||
@@ -69,13 +69,13 @@ func (d *DadaAPI) CheckCallbackValidation(mapData map[string]interface{}) (callb
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) GetOrderCallbackMsg(data []byte) (orderMsg *DadaCallbackMsg, callbackResponse *DadaCallbackResponse) {
|
func (a *API) GetOrderCallbackMsg(data []byte) (msg *CallbackMsg, callbackResponse *CallbackResponse) {
|
||||||
orderMsg = new(DadaCallbackMsg)
|
msg = new(CallbackMsg)
|
||||||
if callbackResponse = d.unmarshalData(data, orderMsg); callbackResponse != nil {
|
if callbackResponse = a.unmarshalData(data, msg); callbackResponse != nil {
|
||||||
return nil, FailedResponse
|
return nil, FailedResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
mapData := structs.Map(orderMsg)
|
mapData := structs.Map(msg)
|
||||||
callbackResponse = d.CheckCallbackValidation(mapData)
|
callbackResponse = a.CheckCallbackValidation(mapData)
|
||||||
return orderMsg, callbackResponse
|
return msg, callbackResponse
|
||||||
}
|
}
|
||||||
176
platformapi/dadaapi/dadaapi.go
Normal file
176
platformapi/dadaapi/dadaapi.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
package dadaapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi"
|
||||||
|
"git.rosy.net.cn/baseapi/platformapi"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
sandboxURL = "http://newopen.qa.imdada.cn/"
|
||||||
|
prodURL = "http://newopen.imdada.cn/"
|
||||||
|
signKey = "signature"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ResponseCodeException = -1
|
||||||
|
ResponseCodeSuccess = 0
|
||||||
|
ResponseCodeSignErr = 2003
|
||||||
|
ResponseCodeRetryLater = 2012
|
||||||
|
ResponseCodeNetworkErr = 2455
|
||||||
|
)
|
||||||
|
|
||||||
|
type API struct {
|
||||||
|
appKey string
|
||||||
|
appSecret string
|
||||||
|
sourceID string
|
||||||
|
url string
|
||||||
|
callbackURL string
|
||||||
|
client *http.Client
|
||||||
|
config *platformapi.APIConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseResult struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Result interface{} `json:"result"`
|
||||||
|
ErrorCode int `json:"errorCode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type City struct {
|
||||||
|
CityName string `json:"cityName"`
|
||||||
|
CityCode string `json:"cityCode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CancelReason struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(appKey, appSecret, sourceId, callbackURL string, isProd bool, config ...*platformapi.APIConfig) *API {
|
||||||
|
curConfig := platformapi.DefAPIConfig
|
||||||
|
if len(config) > 0 {
|
||||||
|
curConfig = *config[0]
|
||||||
|
}
|
||||||
|
api := &API{
|
||||||
|
appKey: appKey,
|
||||||
|
appSecret: appSecret,
|
||||||
|
sourceID: sourceId,
|
||||||
|
callbackURL: callbackURL,
|
||||||
|
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||||
|
config: &curConfig,
|
||||||
|
}
|
||||||
|
if isProd {
|
||||||
|
api.url = prodURL
|
||||||
|
} else {
|
||||||
|
api.url = sandboxURL
|
||||||
|
}
|
||||||
|
return api
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) signParams(mapData map[string]interface{}) string {
|
||||||
|
keys := make([]string, 0)
|
||||||
|
for k := range mapData {
|
||||||
|
if k != signKey {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
finalStr := a.appSecret
|
||||||
|
for _, k := range keys {
|
||||||
|
finalStr += k + fmt.Sprint(mapData[k])
|
||||||
|
}
|
||||||
|
|
||||||
|
finalStr += a.appSecret
|
||||||
|
// baseapi.SugarLogger.Debugf("sign str:%v", finalStr)
|
||||||
|
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AccessAPI(action string, params map[string]interface{}) (retVal *ResponseResult, err error) {
|
||||||
|
params2 := make(map[string]interface{})
|
||||||
|
|
||||||
|
params2["app_key"] = a.appKey
|
||||||
|
params2["timestamp"] = utils.Int64ToStr(utils.GetCurTimestamp())
|
||||||
|
params2["format"] = "json"
|
||||||
|
params2["v"] = "1.0"
|
||||||
|
params2["source_id"] = a.sourceID
|
||||||
|
if params == nil {
|
||||||
|
params2["body"] = ""
|
||||||
|
} else {
|
||||||
|
params2["body"] = string(utils.MustMarshal(params))
|
||||||
|
}
|
||||||
|
params2[signKey] = a.signParams(params2)
|
||||||
|
params2Bytes := utils.MustMarshal(params2)
|
||||||
|
request, _ := http.NewRequest("POST", a.url+action, bytes.NewReader(params2Bytes))
|
||||||
|
request.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (result string, err error) {
|
||||||
|
jsonResult1, err := utils.HTTPResponse2Json(response)
|
||||||
|
if err != nil {
|
||||||
|
return platformapi.ErrLevelGeneralFail, err
|
||||||
|
}
|
||||||
|
code := int(utils.MustInterface2Int64(jsonResult1["code"]))
|
||||||
|
retVal = &ResponseResult{
|
||||||
|
Code: code,
|
||||||
|
ErrorCode: code,
|
||||||
|
Msg: jsonResult1["msg"].(string),
|
||||||
|
Status: jsonResult1["status"].(string),
|
||||||
|
}
|
||||||
|
if code == ResponseCodeSuccess {
|
||||||
|
retVal.Result = jsonResult1["result"]
|
||||||
|
return platformapi.ErrLevelSuccess, nil
|
||||||
|
}
|
||||||
|
baseapi.SugarLogger.Warnf("response business code is not ok, data:%v, code:%v", jsonResult1, code)
|
||||||
|
newErr := utils.NewErrorIntCode(retVal.Msg, code)
|
||||||
|
if code == ResponseCodeRetryLater || code == ResponseCodeNetworkErr {
|
||||||
|
return platformapi.ErrLevelRecoverableErr, newErr
|
||||||
|
}
|
||||||
|
return platformapi.ErrLevelCodeIsNotOK, newErr
|
||||||
|
})
|
||||||
|
|
||||||
|
return retVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) GetCities() (retVal []City, err error) {
|
||||||
|
result, err := a.AccessAPI("api/cityCode/list", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cites := result.Result.([]interface{})
|
||||||
|
for _, v := range cites {
|
||||||
|
v2 := v.(map[string]interface{})
|
||||||
|
city := City{
|
||||||
|
CityName: v2["cityName"].(string),
|
||||||
|
CityCode: v2["cityCode"].(string),
|
||||||
|
}
|
||||||
|
retVal = append(retVal, city)
|
||||||
|
}
|
||||||
|
return retVal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) GetCancelReasons() (retVal []CancelReason, err error) {
|
||||||
|
result, err := a.AccessAPI("api/order/cancel/reasons", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cites := result.Result.([]interface{})
|
||||||
|
for _, v := range cites {
|
||||||
|
v2 := v.(map[string]interface{})
|
||||||
|
reason := CancelReason{
|
||||||
|
ID: int(utils.MustInterface2Int64(v2["id"])),
|
||||||
|
Reason: v2["reason"].(string),
|
||||||
|
}
|
||||||
|
retVal = append(retVal, reason)
|
||||||
|
}
|
||||||
|
return retVal, nil
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dadaapi *DadaAPI
|
dadaapi *API
|
||||||
sugarLogger *zap.SugaredLogger
|
sugarLogger *zap.SugaredLogger
|
||||||
testOrder *OperateOrderRequiredParams
|
testOrder *OperateOrderRequiredParams
|
||||||
)
|
)
|
||||||
@@ -25,13 +25,13 @@ func init() {
|
|||||||
baseapi.Init(sugarLogger)
|
baseapi.Init(sugarLogger)
|
||||||
|
|
||||||
// sandbox
|
// sandbox
|
||||||
dadaapi = NewDadaAPI("dada9623324449cd250", "30c2abbfe8a8780ad5aace46300c64b9", "73753", "http://callback.jxc4.com/dada/order", false)
|
dadaapi = New("dada9623324449cd250", "30c2abbfe8a8780ad5aace46300c64b9", "73753", "http://callback.jxc4.com/dada/order", false)
|
||||||
|
|
||||||
// prod
|
// prod
|
||||||
|
|
||||||
testOrder = &OperateOrderRequiredParams{
|
testOrder = &OperateOrderRequiredParams{
|
||||||
ShopNo: testShopNo,
|
ShopNo: testShopNo,
|
||||||
OriginId: "234242342",
|
OriginID: "234242342",
|
||||||
CityCode: "028",
|
CityCode: "028",
|
||||||
CargoPrice: 12.34,
|
CargoPrice: 12.34,
|
||||||
IsPrepay: 1,
|
IsPrepay: 1,
|
||||||
@@ -52,21 +52,21 @@ func TestSignCallback(t *testing.T) {
|
|||||||
sampleData := `{"signature":"5a277f2519b6011028ff541fb09b8553","client_id":"275000419162381","order_id":"234242342","order_status":1,"cancel_reason":"","cancel_from":0,"dm_id":0,"update_time":1529564947}`
|
sampleData := `{"signature":"5a277f2519b6011028ff541fb09b8553","client_id":"275000419162381","order_id":"234242342","order_status":1,"cancel_reason":"","cancel_from":0,"dm_id":0,"update_time":1529564947}`
|
||||||
mapData := make(map[string]interface{})
|
mapData := make(map[string]interface{})
|
||||||
utils.UnmarshalUseNumber([]byte(sampleData), &mapData)
|
utils.UnmarshalUseNumber([]byte(sampleData), &mapData)
|
||||||
sign := dadaapi.signParamsCallback(mapData)
|
sign := dadaapi.signCallbackParams(mapData)
|
||||||
if sign != mapData["signature"] {
|
if sign != mapData["signature"] {
|
||||||
t.Fatal("sign is not correct")
|
t.Fatal("sign is not correct")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessDada(t *testing.T) {
|
func TestAccessAPI(t *testing.T) {
|
||||||
body := make(map[string]interface{})
|
body := make(map[string]interface{})
|
||||||
body["order_id"] = "fakeorderid"
|
body["order_id"] = "fakeorderid"
|
||||||
result, err := dadaapi.AccessDada("api/order/status/query", body)
|
result, err := dadaapi.AccessAPI("api/order/status/query", body)
|
||||||
|
|
||||||
failed := true
|
failed := true
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err2, ok := err.(*utils.ErrorWithCode); ok {
|
if err2, ok := err.(*utils.ErrorWithCode); ok {
|
||||||
if err2.IntCode() != DadaCodeSignErr {
|
if err2.IntCode() != ResponseCodeSignErr {
|
||||||
failed = false
|
failed = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ func TestGetReasons(t *testing.T) {
|
|||||||
// baseapi.SugarLogger.Debug(result)
|
// baseapi.SugarLogger.Debug(result)
|
||||||
failed := true
|
failed := true
|
||||||
for _, reason := range result {
|
for _, reason := range result {
|
||||||
if reason.Id == 1 {
|
if reason.ID == 1 {
|
||||||
failed = false
|
failed = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ func TestReaddOrder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCancelOrder(t *testing.T) {
|
func TestCancelOrder(t *testing.T) {
|
||||||
result, err := dadaapi.CancelOrder("234242342", ReasonIdClientDontWantItAnymore, "")
|
result, err := dadaapi.CancelOrder("234242342", ReasonIDClientDontWantItAnymore, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
@@ -6,16 +6,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ReasonIdNobodyAccept = 1
|
ReasonIDNobodyAccept = 1
|
||||||
ReasonIdNobodyPickup = 2
|
ReasonIDNobodyPickup = 2
|
||||||
ReasonIdCourierIsPig = 3
|
ReasonIDCourierIsPig = 3
|
||||||
ReasonIdClientCanceled = 4
|
ReasonIDClientCanceled = 4
|
||||||
ReasonIdOrderIsWrong = 5
|
ReasonIDOrderIsWrong = 5
|
||||||
ReasonIdCourierWantMeCancel = 34
|
ReasonIDCourierWantMeCancel = 34
|
||||||
ReasonIdCourierDontWantToPickup = 35
|
ReasonIDCourierDontWantToPickup = 35
|
||||||
ReasonIdClientDontWantItAnymore = 36
|
ReasonIDClientDontWantItAnymore = 36
|
||||||
ReasonIdCourierShirk = 37
|
ReasonIDCourierShirk = 37
|
||||||
ReasonIdOther = 10000
|
ReasonIDOther = 10000
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -33,7 +33,7 @@ const (
|
|||||||
|
|
||||||
type OperateOrderRequiredParams struct {
|
type OperateOrderRequiredParams struct {
|
||||||
ShopNo string `json:"shop_no"`
|
ShopNo string `json:"shop_no"`
|
||||||
OriginId string `json:"origin_id"`
|
OriginID string `json:"origin_id"`
|
||||||
CityCode string `json:"city_code"`
|
CityCode string `json:"city_code"`
|
||||||
CargoPrice float64 `json:"cargo_price"`
|
CargoPrice float64 `json:"cargo_price"`
|
||||||
IsPrepay int `json:"is_prepay"`
|
IsPrepay int `json:"is_prepay"`
|
||||||
@@ -58,10 +58,10 @@ type CancelOrderResponse struct {
|
|||||||
DeductFee float64 `json:"deduct_fee"`
|
DeductFee float64 `json:"deduct_fee"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) QueryOrderInfo(orderId string) (retVal map[string]interface{}, err error) {
|
func (a *API) QueryOrderInfo(orderId string) (retVal map[string]interface{}, err error) {
|
||||||
params := make(map[string]interface{})
|
params := make(map[string]interface{})
|
||||||
params["order_id"] = orderId
|
params["order_id"] = orderId
|
||||||
result, err := d.AccessDada("api/order/status/query", params)
|
result, err := a.AccessAPI("api/order/status/query", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -87,12 +87,12 @@ func map2CreateOrderResponse(mapData map[string]interface{}) *CreateOrderRespons
|
|||||||
return retVal
|
return retVal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) operateOrder(action string, orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
func (a *API) operateOrder(action string, orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
||||||
params := structs.Map(orderInfo)
|
params := structs.Map(orderInfo)
|
||||||
params["callback"] = d.callbackURL
|
params["callback"] = a.callbackURL
|
||||||
allParams := utils.MergeMaps(params, addParams)
|
allParams := utils.MergeMaps(params, addParams)
|
||||||
|
|
||||||
result, err := d.AccessDada(action, allParams)
|
result, err := a.AccessAPI(action, allParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -100,25 +100,25 @@ func (d *DadaAPI) operateOrder(action string, orderInfo *OperateOrderRequiredPar
|
|||||||
return map2CreateOrderResponse(result.Result.(map[string]interface{})), nil
|
return map2CreateOrderResponse(result.Result.(map[string]interface{})), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) AddOrder(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
func (a *API) AddOrder(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
||||||
return d.operateOrder("api/order/addOrder", orderInfo, addParams)
|
return a.operateOrder("api/order/addOrder", orderInfo, addParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) ReaddOrder(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
func (a *API) ReaddOrder(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
||||||
return d.operateOrder("api/order/reAddOrder", orderInfo, addParams)
|
return a.operateOrder("api/order/reAddOrder", orderInfo, addParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) QueryDeliverFee(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
func (a *API) QueryDeliverFee(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
||||||
return d.operateOrder("api/order/queryDeliverFee", orderInfo, addParams)
|
return a.operateOrder("api/order/queryDeliverFee", orderInfo, addParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) AddOrderAfterQuery(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
func (a *API) AddOrderAfterQuery(orderInfo *OperateOrderRequiredParams, addParams map[string]interface{}) (retVal *CreateOrderResponse, err error) {
|
||||||
return d.operateOrder("api/order/addAfterQuery", orderInfo, addParams)
|
return a.operateOrder("api/order/addAfterQuery", orderInfo, addParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DadaAPI) CancelOrder(orderId string, cancelOrderReasonId int, cancelOrderReason string) (retVal *CancelOrderResponse, err error) {
|
func (a *API) CancelOrder(orderId string, cancelOrderReasonId int, cancelOrderReason string) (retVal *CancelOrderResponse, err error) {
|
||||||
mapData := utils.Params2Map("order_id", orderId, "cancel_reason_id", cancelOrderReasonId, "cancel_reason", cancelOrderReason)
|
mapData := utils.Params2Map("order_id", orderId, "cancel_reason_id", cancelOrderReasonId, "cancel_reason", cancelOrderReason)
|
||||||
result, err := d.AccessDada("api/order/formalCancel", mapData)
|
result, err := a.AccessAPI("api/order/formalCancel", mapData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
69
platformapi/elmapi/callback.go
Normal file
69
platformapi/elmapi/callback.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package elmapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi"
|
||||||
|
"git.rosy.net.cn/baseapi/platformapi"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
"github.com/fatih/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://open.shop.ele.me/openapi/documents/callback
|
||||||
|
const (
|
||||||
|
MsgTypeOrderValid = 10
|
||||||
|
MsgTypeMerchantValid = 12
|
||||||
|
MsgTypeOrderCanceled = 14
|
||||||
|
MsgTypeMerchantInvalid = 15
|
||||||
|
MsgTypeOrderForceInvalid = 17
|
||||||
|
MsgTypeOrderFinished = 18
|
||||||
|
)
|
||||||
|
|
||||||
|
type CallbackResponse struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallbackMsg struct {
|
||||||
|
AppID int `json:"appId"`
|
||||||
|
RequestID string `json:"requestId"`
|
||||||
|
Type int `json:"type"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
ShopID int `json:"shopId"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
UserID int64 `json:"userId"`
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
SuccessResponse = &CallbackResponse{"ok"}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *API) unmarshalData(data []byte, msg interface{}) (callbackResponse *CallbackResponse) {
|
||||||
|
err := utils.UnmarshalUseNumber(data, msg)
|
||||||
|
if err != nil {
|
||||||
|
return &CallbackResponse{
|
||||||
|
Message: fmt.Sprintf(platformapi.ErrStrUnmarshalError, data, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *API) CheckCallbackValidation(mapData map[string]interface{}) (callbackResponse *CallbackResponse) {
|
||||||
|
sign := e.signParamsMap(mapData, "")
|
||||||
|
if remoteSign, _ := mapData[signKey].(string); sign != remoteSign {
|
||||||
|
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, remoteSign)
|
||||||
|
return &CallbackResponse{Message: platformapi.ErrStrCallbackSignatureIsWrong}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *API) GetCallbackMsg(data []byte) (msg *CallbackMsg, callbackResponse *CallbackResponse) {
|
||||||
|
msg = new(CallbackMsg)
|
||||||
|
if callbackResponse = e.unmarshalData(data, msg); callbackResponse != nil {
|
||||||
|
return nil, callbackResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
mapData := structs.Map(msg)
|
||||||
|
callbackResponse = e.CheckCallbackValidation(mapData)
|
||||||
|
return msg, callbackResponse
|
||||||
|
}
|
||||||
155
platformapi/elmapi/elmapi.go
Normal file
155
platformapi/elmapi/elmapi.go
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package elmapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi"
|
||||||
|
"git.rosy.net.cn/baseapi/platformapi"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
sandboxURL = "https://open-api-sandbox.shop.ele.me/api/v1/"
|
||||||
|
prodURL = "https://open-api.shop.ele.me/api/v1/"
|
||||||
|
signKey = "signature"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResponseResult struct {
|
||||||
|
ID string
|
||||||
|
Result interface{}
|
||||||
|
Error map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type API struct {
|
||||||
|
token string
|
||||||
|
appKey string
|
||||||
|
secret string
|
||||||
|
url *url.URL
|
||||||
|
client *http.Client
|
||||||
|
config *platformapi.APIConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type payload struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
Nop string `json:"nop"`
|
||||||
|
Metas map[string]interface{} `json:"metas"`
|
||||||
|
Params map[string]interface{} `json:"params"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(token, appKey, secret string, isProd bool, config ...*platformapi.APIConfig) *API {
|
||||||
|
curConfig := platformapi.DefAPIConfig
|
||||||
|
if len(config) > 0 {
|
||||||
|
curConfig = *config[0]
|
||||||
|
}
|
||||||
|
api := &API{
|
||||||
|
token: token,
|
||||||
|
appKey: appKey,
|
||||||
|
secret: secret,
|
||||||
|
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||||
|
config: &curConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
if isProd {
|
||||||
|
api.url, _ = url.Parse(prodURL)
|
||||||
|
} else {
|
||||||
|
api.url, _ = url.Parse(sandboxURL)
|
||||||
|
}
|
||||||
|
return api
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) signParamsMap(mapData map[string]interface{}, prefix string) string {
|
||||||
|
keyValues := make([]string, 0)
|
||||||
|
for k, v := range mapData {
|
||||||
|
if k != signKey {
|
||||||
|
vStr := ""
|
||||||
|
if prefix == "" { // callback sign
|
||||||
|
vStr = fmt.Sprint(v)
|
||||||
|
} else { // call sign
|
||||||
|
vBytes := utils.MustMarshal(v)
|
||||||
|
vStr = string(vBytes)
|
||||||
|
}
|
||||||
|
keyValues = append(keyValues, k+"="+vStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keyValues)
|
||||||
|
finalStr := prefix + strings.Join(keyValues, "") + a.secret
|
||||||
|
// baseapi.SugarLogger.Debugf("sign str:%v", finalStr)
|
||||||
|
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) signParams(action string, pl *payload) string {
|
||||||
|
mapData := utils.MergeMaps(pl.Metas, pl.Params)
|
||||||
|
return a.signParamsMap(mapData, action+a.token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AccessAPI(action string, params map[string]interface{}) (retVal *ResponseResult, err error) {
|
||||||
|
if params == nil {
|
||||||
|
params = make(map[string]interface{}, 0)
|
||||||
|
}
|
||||||
|
metas := map[string]interface{}{
|
||||||
|
"app_key": a.appKey,
|
||||||
|
"timestamp": utils.GetCurTimestamp(),
|
||||||
|
}
|
||||||
|
|
||||||
|
pl := &payload{
|
||||||
|
Token: a.token,
|
||||||
|
Nop: "1.0.0",
|
||||||
|
Metas: metas,
|
||||||
|
Params: params,
|
||||||
|
Action: action,
|
||||||
|
ID: utils.GetUUID(),
|
||||||
|
}
|
||||||
|
|
||||||
|
pl.Signature = a.signParams(action, pl)
|
||||||
|
|
||||||
|
request := &http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: a.url,
|
||||||
|
Header: http.Header{
|
||||||
|
"Content-Type": []string{"application/json; charset=utf-8"},
|
||||||
|
"Content-Encoding": []string{"gzip, deflate"},
|
||||||
|
"User-Agent": []string{"eleme-golang-api"},
|
||||||
|
// "x-eleme-requestid": []string{payload.Id},
|
||||||
|
},
|
||||||
|
|
||||||
|
Body: ioutil.NopCloser(strings.NewReader(string(utils.MustMarshal(pl)))),
|
||||||
|
}
|
||||||
|
err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (result string, err error) {
|
||||||
|
jsonResult1, err := utils.HTTPResponse2Json(response)
|
||||||
|
if err != nil {
|
||||||
|
return platformapi.ErrLevelGeneralFail, err
|
||||||
|
}
|
||||||
|
resultError, _ := jsonResult1["error"].(map[string]interface{})
|
||||||
|
retVal = &ResponseResult{
|
||||||
|
ID: jsonResult1["id"].(string),
|
||||||
|
Error: resultError,
|
||||||
|
Result: jsonResult1["result"],
|
||||||
|
}
|
||||||
|
errinfoMap := retVal.Error
|
||||||
|
if errinfoMap == nil {
|
||||||
|
return platformapi.ErrLevelSuccess, nil
|
||||||
|
}
|
||||||
|
code := errinfoMap["code"].(string)
|
||||||
|
baseapi.SugarLogger.Warnf("response business code is not ok, data:%v, code:%v", jsonResult1, code)
|
||||||
|
newErr := utils.NewErrorCode(errinfoMap["message"].(string), code)
|
||||||
|
if code == "EXCEED_LIMIT" {
|
||||||
|
return platformapi.ErrLevelExceedLimit, newErr
|
||||||
|
} else if code == "SERVER_ERROR" || code == "BIZ_SYSTEM_ERROR" || code == "BIZ_1006" || code == "BUSINESS_ERROR" {
|
||||||
|
return platformapi.ErrLevelRecoverableErr, newErr
|
||||||
|
} else {
|
||||||
|
return platformapi.ErrLevelCodeIsNotOK, newErr
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return retVal, err
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
elmapi *ELMAPI
|
elmapi *API
|
||||||
sugarLogger *zap.SugaredLogger
|
sugarLogger *zap.SugaredLogger
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,18 +20,18 @@ func init() {
|
|||||||
baseapi.Init(sugarLogger)
|
baseapi.Init(sugarLogger)
|
||||||
|
|
||||||
// sandbox
|
// sandbox
|
||||||
// elmapi = NewELMAPI("b4f7e424475c3758c111dc60ceec3e2a", "RwT214gAsS", "56afff4b9ebd8a7eb532d18fa33f17be57f9b9db", false)
|
// elmapi = New("b4f7e424475c3758c111dc60ceec3e2a", "RwT214gAsS", "56afff4b9ebd8a7eb532d18fa33f17be57f9b9db", false)
|
||||||
|
|
||||||
// prod
|
// prod
|
||||||
elmapi = NewELMAPI("bab2a27f99562f394b411dbb9a6214da", "KLRDcOZGrk", "1fc221f8265506531da36fb613d5f5ad673f2e9a", true)
|
elmapi = New("bab2a27f99562f394b411dbb9a6214da", "KLRDcOZGrk", "1fc221f8265506531da36fb613d5f5ad673f2e9a", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTest(t *testing.T) {
|
func TestTest(t *testing.T) {
|
||||||
sugarLogger.Debug(utils.GetCurTimeStr())
|
sugarLogger.Debug(utils.GetCurTimeStr())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessELM(t *testing.T) {
|
func TestAccessAPI(t *testing.T) {
|
||||||
result, err := elmapi.AccessELM("eleme.user.getUser", nil)
|
result, err := elmapi.AccessAPI("eleme.user.getUser", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error when accessing AccessJDQuery result:%v, error:%v", result, err)
|
t.Fatalf("Error when accessing AccessJDQuery result:%v, error:%v", result, err)
|
||||||
} else {
|
} else {
|
||||||
@@ -59,6 +59,6 @@ func TestCallbackSign(t *testing.T) {
|
|||||||
jsonStr := `{"requestId":"200016348669063447","type":18,"appId":78247922,"message":"{\"orderId\":\"3024923917769149510\",\"state\":\"settled\",\"shopId\":157492364,\"updateTime\":1529465510,\"role\":1}","shopId":157492364,"timestamp":1529465510255,"signature":"D65F917D93B4F599B85486C799599141","userId":336072266322770688}`
|
jsonStr := `{"requestId":"200016348669063447","type":18,"appId":78247922,"message":"{\"orderId\":\"3024923917769149510\",\"state\":\"settled\",\"shopId\":157492364,\"updateTime\":1529465510,\"role\":1}","shopId":157492364,"timestamp":1529465510255,"signature":"D65F917D93B4F599B85486C799599141","userId":336072266322770688}`
|
||||||
msg, response := elmapi.GetCallbackMsg([]byte(jsonStr))
|
msg, response := elmapi.GetCallbackMsg([]byte(jsonStr))
|
||||||
if response != nil || msg == nil {
|
if response != nil || msg == nil {
|
||||||
t.Fatal("Something wrong")
|
t.Fatal(response, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
23
platformapi/elmapi/order.go
Normal file
23
platformapi/elmapi/order.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package elmapi
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrderStatusPending = "pending"
|
||||||
|
OrderStatusUnprocessed = "unprocessed"
|
||||||
|
OrderStatusRefunding = "refunding"
|
||||||
|
OrderStatusValid = "valid"
|
||||||
|
OrderStatusInvalid = "invalid"
|
||||||
|
OrderStatusSettled = "settled"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *API) GetOrder(orderID string) (map[string]interface{}, error) {
|
||||||
|
result, err := a.AccessAPI("eleme.order.getOrder", map[string]interface{}{
|
||||||
|
"orderId": orderID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
innerResult := result.Result.(map[string]interface{})
|
||||||
|
return innerResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
121
platformapi/jdapi/callback.go
Normal file
121
platformapi/jdapi/callback.go
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package jdapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi"
|
||||||
|
"git.rosy.net.cn/baseapi/platformapi"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CallbackResponse struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallbackOrderMsg struct {
|
||||||
|
ID int `json:"-"` // 用于传递Jdorder的主键值,减少一次读库操作
|
||||||
|
BillID string `json:"billId"`
|
||||||
|
StatusID string `json:"statusId"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallbackDeliveryStatusMsg struct {
|
||||||
|
OrderID string `json:"orderId"`
|
||||||
|
DeliveryStatusTime string `json:"deliveryStatusTime"`
|
||||||
|
DeliveryManNo string `json:"deliveryManNo"`
|
||||||
|
DeliveryManName string `json:"deliveryManName"`
|
||||||
|
DeliveryManPhone string `json:"deliveryManPhone"`
|
||||||
|
DeliveryCarrierNo string `json:"deliveryCarrierNo"`
|
||||||
|
DeliveryCarrierName string `json:"deliveryCarrierName"`
|
||||||
|
DeliveryStatus int `json:"deliveryStatus"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
FailType string `json:"failType"`
|
||||||
|
CreatePin string `json:"createPin"`
|
||||||
|
OpTime int64 `json:"opTime"`
|
||||||
|
InputTime string `json:"inputTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
SuccessResponse = &CallbackResponse{Code: "0", Msg: "success", Data: ""}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *API) unmarshalData(strData string, msg interface{}) (callbackResponse *CallbackResponse) {
|
||||||
|
err := utils.UnmarshalUseNumber([]byte(strData), msg)
|
||||||
|
if err != nil {
|
||||||
|
return &CallbackResponse{
|
||||||
|
Code: ResponseCodeAbnormalParam,
|
||||||
|
Msg: fmt.Sprintf(platformapi.ErrStrUnmarshalError, strData, err),
|
||||||
|
Data: strData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) CheckCallbackValidation(request *http.Request) (callbackResponse *CallbackResponse) {
|
||||||
|
mapData := make(map[string]interface{})
|
||||||
|
mapData["token"] = request.FormValue("token")
|
||||||
|
mapData["app_key"] = request.FormValue("app_key")
|
||||||
|
mapData["timestamp"] = request.FormValue("timestamp")
|
||||||
|
mapData["format"] = request.FormValue("format")
|
||||||
|
mapData["app_secret"] = a.appSecret
|
||||||
|
mapData["v"] = request.FormValue("v")
|
||||||
|
mapData[paramJson] = request.FormValue(paramJson)
|
||||||
|
|
||||||
|
sign := a.signParams(mapData)
|
||||||
|
if sign != request.FormValue(signKey) {
|
||||||
|
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, request.FormValue(signKey))
|
||||||
|
return &CallbackResponse{
|
||||||
|
Code: ResponseCodeInvalidSign,
|
||||||
|
Msg: platformapi.ErrStrCallbackSignatureIsWrong,
|
||||||
|
Data: string(utils.MustMarshal(mapData)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) getCommonOrderCallbackMsg(request *http.Request, msg interface{}, needDecode bool) (callbackResponse *CallbackResponse) {
|
||||||
|
if callbackResponse = a.CheckCallbackValidation(request); callbackResponse != nil {
|
||||||
|
return callbackResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
jdParamJSON := request.FormValue(paramJson)
|
||||||
|
if needDecode {
|
||||||
|
if jdParamJSON2, err := url.QueryUnescape(jdParamJSON); err == nil {
|
||||||
|
jdParamJSON = jdParamJSON2
|
||||||
|
} else {
|
||||||
|
return &CallbackResponse{
|
||||||
|
Code: ResponseCodeAbnormalParam,
|
||||||
|
Msg: fmt.Sprintf(platformapi.ErrStrUnescapeError, jdParamJSON, err),
|
||||||
|
Data: jdParamJSON,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if callbackResponse = a.unmarshalData(jdParamJSON, msg); callbackResponse != nil {
|
||||||
|
return callbackResponse
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) GetOrderCallbackMsg(request *http.Request) (msg *CallbackOrderMsg, callbackResponse *CallbackResponse) {
|
||||||
|
msg = new(CallbackOrderMsg)
|
||||||
|
callbackResponse = a.getCommonOrderCallbackMsg(request, msg, false)
|
||||||
|
return msg, callbackResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) GetOrderApplyCancelCallbackMsg(request *http.Request) (msg *CallbackOrderMsg, callbackResponse *CallbackResponse) {
|
||||||
|
msg = new(CallbackOrderMsg)
|
||||||
|
callbackResponse = a.getCommonOrderCallbackMsg(request, msg, true)
|
||||||
|
return msg, callbackResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) GetOrderDeliveryCallbackMsg(request *http.Request) (msg *CallbackDeliveryStatusMsg, callbackResponse *CallbackResponse) {
|
||||||
|
msg = new(CallbackDeliveryStatusMsg)
|
||||||
|
callbackResponse = a.getCommonOrderCallbackMsg(request, msg, true)
|
||||||
|
return msg, callbackResponse
|
||||||
|
}
|
||||||
342
platformapi/jdapi/jdapi.go
Normal file
342
platformapi/jdapi/jdapi.go
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
package jdapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi/platformapi"
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
paramJson = "jd_param_json"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ResponseCodeSuccess 操作成功
|
||||||
|
ResponseCodeSuccess = "0"
|
||||||
|
// ResponseCodeAccessFailed 操作失败,请重试,如还不能正常提供服务,可以提交工单(https://opengd.jd.com)详细说明一下,开放平台跟进回复。
|
||||||
|
ResponseCodeAccessFailed = "-1"
|
||||||
|
// ResponseCodeFailedCanAutoRetry 操作失败,系统会自动重试,如还不能正常提供服务,可以提交工单(https://opengd.jd.com)详细说明一下,开放平台跟进回复。
|
||||||
|
ResponseCodeFailedCanAutoRetry = "-10000"
|
||||||
|
ResponseCodeFailedAccessDB = "10000"
|
||||||
|
// ResponseCodeMissingMandatoryParam 请求参数中缺失必填项信息,请检查,如不清楚,请访问到家开放平台(https://opendj.jd.com)API分组有接口详细说明。
|
||||||
|
ResponseCodeMissingMandatoryParam = "10005"
|
||||||
|
ResponseCodeInvalidToken = "10013"
|
||||||
|
ResponseCodeInvalidSign = "10014"
|
||||||
|
ResponseCodeAbnormalParam = "10015"
|
||||||
|
ResponseCodeMethodNotExist = "10018"
|
||||||
|
ResponseCodeExceedLimit = "10032"
|
||||||
|
|
||||||
|
ResponseCodeTimeout = "100022"
|
||||||
|
ResponseCodeTomcateFailed = "100023"
|
||||||
|
ResponseCodeLoadUnexpected = "100024"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
prodURL = "https://openo2o.jd.com/djapi/%s"
|
||||||
|
signKey = "sign"
|
||||||
|
AllPage = 0
|
||||||
|
DefaultPageSize = 50
|
||||||
|
)
|
||||||
|
|
||||||
|
type API struct {
|
||||||
|
token string
|
||||||
|
appKey string
|
||||||
|
appSecret string
|
||||||
|
client *http.Client
|
||||||
|
config *platformapi.APIConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
InnerCodeIsNotOk = "JD result inner code is not ok"
|
||||||
|
|
||||||
|
exceedLimitCodes = map[string]int{
|
||||||
|
ResponseCodeExceedLimit: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo replace all magic number
|
||||||
|
canRetryCodes = map[string]int{
|
||||||
|
ResponseCodeFailedCanAutoRetry: 1,
|
||||||
|
ResponseCodeAccessFailed: 1,
|
||||||
|
ResponseCodeFailedAccessDB: 1,
|
||||||
|
ResponseCodeTimeout: 1,
|
||||||
|
ResponseCodeTomcateFailed: 1,
|
||||||
|
ResponseCodeLoadUnexpected: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
innerCodeKeys = []string{"code", "retCode", "errorCode"}
|
||||||
|
|
||||||
|
innerCodeOKCodes = map[string]int{
|
||||||
|
"None": 1,
|
||||||
|
"0": 1,
|
||||||
|
"1": 1,
|
||||||
|
"200": 1,
|
||||||
|
"190005": 1, // 部分失败
|
||||||
|
}
|
||||||
|
|
||||||
|
noPageInnerDataKeys = []string{"result", "data"}
|
||||||
|
havePageInner2DataKeys = []string{"result", "resultList"}
|
||||||
|
havePageTotalCountKeys = []string{"totalCount", "count"}
|
||||||
|
)
|
||||||
|
|
||||||
|
type PageResultParser func(map[string]interface{}, int) ([]interface{}, int, error)
|
||||||
|
|
||||||
|
func (a *API) signParams(jdParams map[string]interface{}) string {
|
||||||
|
var keys []string
|
||||||
|
for k := range jdParams {
|
||||||
|
if k != "app_secret" && k != signKey {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
secretStr := fmt.Sprint(jdParams["app_secret"])
|
||||||
|
allStr := secretStr
|
||||||
|
for _, k := range keys {
|
||||||
|
allStr += k + fmt.Sprint(jdParams[k])
|
||||||
|
}
|
||||||
|
allStr = allStr + secretStr
|
||||||
|
|
||||||
|
return fmt.Sprintf("%X", md5.Sum([]byte(allStr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateURL(baseURL, apiStr string, params map[string]interface{}) string {
|
||||||
|
fullURL := ""
|
||||||
|
|
||||||
|
if params != nil {
|
||||||
|
for k, v := range params {
|
||||||
|
if fullURL == "" {
|
||||||
|
fullURL = "?"
|
||||||
|
} else {
|
||||||
|
fullURL += "&"
|
||||||
|
}
|
||||||
|
fullURL += k + "=" + url.QueryEscape(fmt.Sprint(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf(baseURL, apiStr) + fullURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(token, appKey, appSecret string, config ...*platformapi.APIConfig) *API {
|
||||||
|
curConfig := platformapi.DefAPIConfig
|
||||||
|
if len(config) > 0 {
|
||||||
|
curConfig = *config[0]
|
||||||
|
}
|
||||||
|
return &API{
|
||||||
|
token: token,
|
||||||
|
appKey: appKey,
|
||||||
|
appSecret: appSecret,
|
||||||
|
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||||
|
config: &curConfig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AccessAPI(apiStr string, jdParams map[string]interface{}) (retVal map[string]interface{}, err error) {
|
||||||
|
params := make(map[string]interface{})
|
||||||
|
params["v"] = "1.0"
|
||||||
|
params["format"] = "json"
|
||||||
|
params["app_key"] = a.appKey
|
||||||
|
params["app_secret"] = a.appSecret
|
||||||
|
params["token"] = a.token
|
||||||
|
|
||||||
|
if jdParams == nil {
|
||||||
|
jdParams = make(map[string]interface{}, 0)
|
||||||
|
}
|
||||||
|
jdParamStr, err := json.Marshal(jdParams)
|
||||||
|
if err != nil {
|
||||||
|
baseapi.SugarLogger.Errorf("Error when marshal %v, error:%v", jdParams, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
params["jd_param_json"] = string(jdParamStr)
|
||||||
|
params["timestamp"] = utils.GetCurTimeStr()
|
||||||
|
sign := a.signParams(params)
|
||||||
|
params[signKey] = sign
|
||||||
|
|
||||||
|
url, _ := url.Parse(generateURL(prodURL, apiStr, params))
|
||||||
|
request := &http.Request{
|
||||||
|
Method: "GET",
|
||||||
|
URL: url,
|
||||||
|
}
|
||||||
|
err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (errLevel string, err error) {
|
||||||
|
jsonResult1, err := utils.HTTPResponse2Json(response)
|
||||||
|
if err != nil {
|
||||||
|
return platformapi.ErrLevelGeneralFail, platformapi.ErrResponseDataFormatWrong
|
||||||
|
}
|
||||||
|
code := jsonResult1["code"].(string)
|
||||||
|
if code == ResponseCodeSuccess {
|
||||||
|
retVal = jsonResult1
|
||||||
|
return platformapi.ErrLevelSuccess, nil
|
||||||
|
}
|
||||||
|
baseapi.SugarLogger.Warnf("response business code is not ok, data:%v, code:%v", jsonResult1, code)
|
||||||
|
newErr := utils.NewErrorCode(jsonResult1["msg"].(string), code)
|
||||||
|
if _, ok := exceedLimitCodes[code]; ok {
|
||||||
|
return platformapi.ErrLevelExceedLimit, newErr
|
||||||
|
} else if _, ok := canRetryCodes[code]; ok {
|
||||||
|
return platformapi.ErrLevelRecoverableErr, newErr
|
||||||
|
} else {
|
||||||
|
return platformapi.ErrLevelCodeIsNotOK, newErr
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return retVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AccessAPINoPage(apiStr string, jdParams map[string]interface{}, keyToRemove, keyToKeep []string) (interface{}, error) {
|
||||||
|
jsonResult, err := a.AccessAPI(apiStr, jdParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data map[string]interface{}
|
||||||
|
if err := utils.UnmarshalUseNumber([]byte(jsonResult["data"].(string)), &data); err != nil {
|
||||||
|
return nil, platformapi.ErrResponseDataFormatWrong
|
||||||
|
}
|
||||||
|
|
||||||
|
innerCode := ""
|
||||||
|
for _, innerCodeKey := range innerCodeKeys {
|
||||||
|
if innerCode2, ok := data[innerCodeKey]; ok {
|
||||||
|
innerCode = forceInnerCode2Str(innerCode2)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := innerCodeOKCodes[innerCode]; ok {
|
||||||
|
for _, innerDataKey := range noPageInnerDataKeys {
|
||||||
|
if innerData, ok := data[innerDataKey]; ok {
|
||||||
|
return utils.DictKeysMan(innerData, keyToRemove, keyToKeep), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
baseapi.SugarLogger.Errorf("can not find inner data, data:%v", jsonResult)
|
||||||
|
return nil, platformapi.ErrResponseDataFormatWrong
|
||||||
|
} else {
|
||||||
|
// todo 可以把具体错误消息放进来
|
||||||
|
return nil, utils.NewErrorCode(InnerCodeIsNotOk, innerCode, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NormalHavePageResultParser(data map[string]interface{}, totalCount int) ([]interface{}, int, error) {
|
||||||
|
var result map[string]interface{}
|
||||||
|
var retVal []interface{}
|
||||||
|
|
||||||
|
tempResult := data["result"]
|
||||||
|
if resultStr, ok := tempResult.(string); ok {
|
||||||
|
if err := utils.UnmarshalUseNumber([]byte(resultStr), &tempResult); err != nil {
|
||||||
|
return nil, 0, platformapi.ErrResponseDataFormatWrong
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = tempResult.(map[string]interface{})
|
||||||
|
|
||||||
|
if totalCount == 0 {
|
||||||
|
for _, totalCountKey := range havePageTotalCountKeys {
|
||||||
|
if totalCount2, ok := result[totalCountKey]; ok {
|
||||||
|
totalCountInt64, _ := totalCount2.(json.Number).Int64()
|
||||||
|
totalCount = int(totalCountInt64)
|
||||||
|
if totalCount == 0 {
|
||||||
|
return make([]interface{}, 0), 0, nil
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if totalCount == 0 {
|
||||||
|
baseapi.SugarLogger.Errorf("can not find totalCount key, data:%v", result)
|
||||||
|
return nil, 0, platformapi.ErrResponseDataFormatWrong
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, inner2ResultKey := range havePageInner2DataKeys {
|
||||||
|
if inner2Result, ok := result[inner2ResultKey]; ok {
|
||||||
|
|
||||||
|
if inner2ResultStr, ok := inner2Result.(string); ok {
|
||||||
|
err := utils.UnmarshalUseNumber([]byte(inner2ResultStr), &retVal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, platformapi.ErrResponseDataFormatWrong
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
retVal = inner2Result.([]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal, totalCount, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
baseapi.SugarLogger.Errorf("can not find result key, data:%v", result)
|
||||||
|
return nil, 0, platformapi.ErrResponseDataFormatWrong
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AccessAPIHavePage(apiStr string, jdParams map[string]interface{}, keyToRemove, keyToKeep []string, pageResultParser PageResultParser) ([]interface{}, error) {
|
||||||
|
if pageResultParser == nil {
|
||||||
|
pageResultParser = NormalHavePageResultParser
|
||||||
|
}
|
||||||
|
|
||||||
|
localJdParams := make(map[string]interface{})
|
||||||
|
if jdParams != nil && len(jdParams) > 0 {
|
||||||
|
for k, v := range jdParams {
|
||||||
|
localJdParams[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCount := 0
|
||||||
|
pageNo := AllPage
|
||||||
|
pageSize := DefaultPageSize
|
||||||
|
if tempPageNo, ok := localJdParams["pageNo"]; ok {
|
||||||
|
pageNo = tempPageNo.(int)
|
||||||
|
}
|
||||||
|
if tempPageSize, ok := localJdParams["pageSize"]; ok {
|
||||||
|
pageSize = tempPageSize.(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
curPage := pageNo
|
||||||
|
if curPage == AllPage {
|
||||||
|
curPage = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
retVal := make([]interface{}, 0)
|
||||||
|
for {
|
||||||
|
localJdParams["pageNo"] = curPage
|
||||||
|
localJdParams["pageSize"] = pageSize
|
||||||
|
jsonResult, err := a.AccessAPI(apiStr, localJdParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var data map[string]interface{}
|
||||||
|
if err := utils.UnmarshalUseNumber([]byte(jsonResult["data"].(string)), &data); err != nil {
|
||||||
|
return nil, platformapi.ErrResponseDataFormatWrong
|
||||||
|
}
|
||||||
|
|
||||||
|
innerCode := forceInnerCode2Str(data["code"])
|
||||||
|
if innerCode != "0" && innerCode != "200" {
|
||||||
|
// todo 可以把具体错误消息放进来
|
||||||
|
return nil, utils.NewErrorCode(InnerCodeIsNotOk, innerCode, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
inResult, totalCount2, err := pageResultParser(data, totalCount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
totalCount = totalCount2
|
||||||
|
|
||||||
|
inResult = utils.DictKeysMan(inResult, keyToRemove, keyToKeep).([]interface{})
|
||||||
|
retVal = append(retVal, inResult...)
|
||||||
|
|
||||||
|
if curPage == pageNo || curPage*pageSize >= totalCount {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
curPage++
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func forceInnerCode2Str(innerCode interface{}) string {
|
||||||
|
if innerCodeStr, ok := innerCode.(string); ok {
|
||||||
|
return innerCodeStr
|
||||||
|
}
|
||||||
|
return utils.Int64ToStr(utils.MustInterface2Int64(innerCode))
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
jdapi *JDAPI
|
jdapi *API
|
||||||
sugarLogger *zap.SugaredLogger
|
sugarLogger *zap.SugaredLogger
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,18 +19,18 @@ func init() {
|
|||||||
logger, _ := zap.NewDevelopment()
|
logger, _ := zap.NewDevelopment()
|
||||||
sugarLogger = logger.Sugar()
|
sugarLogger = logger.Sugar()
|
||||||
baseapi.Init(sugarLogger)
|
baseapi.Init(sugarLogger)
|
||||||
jdapi = NewJDAPI("91633f2a-c5f5-4982-a925-a220d19095c3", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4")
|
jdapi = New("91633f2a-c5f5-4982-a925-a220d19095c3", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4")
|
||||||
// jdapi = NewJDAPI("c8854ef2-f80a-45ee-aceb-dc8014d646f8", "06692746f7224695ad4788ce340bc854", "d6b42a35a7414a5490d811654d745c84")
|
// jdapi = New("c8854ef2-f80a-45ee-aceb-dc8014d646f8", "06692746f7224695ad4788ce340bc854", "d6b42a35a7414a5490d811654d745c84")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTest(t *testing.T) {
|
func TestTest(t *testing.T) {
|
||||||
sugarLogger.Debug(utils.GetCurTimeStr())
|
sugarLogger.Debug(utils.GetCurTimeStr())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessJDQuery(t *testing.T) {
|
func TestAccessAPI(t *testing.T) {
|
||||||
result, err := jdapi.AccessJDQuery("address/allcities", nil)
|
result, err := jdapi.AccessAPI("address/allcities", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error when accessing AccessJDQuery: %v", err)
|
t.Fatalf("Error when accessing AccessAPI: %v", err)
|
||||||
} else {
|
} else {
|
||||||
code := result["code"].(string)
|
code := result["code"].(string)
|
||||||
if code != "0" {
|
if code != "0" {
|
||||||
@@ -39,10 +39,10 @@ func TestAccessJDQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessJDQueryNoPage(t *testing.T) {
|
func TestAccessAPINoPage(t *testing.T) {
|
||||||
result, err := jdapi.AccessJDQueryNoPage("address/allcities", nil, []string{"yn"}, nil)
|
result, err := jdapi.AccessAPINoPage("address/allcities", nil, []string{"yn"}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("AccessJDQueryNoPage return error:%v", err)
|
t.Fatalf("TestAccessAPINoPage return error:%v", err)
|
||||||
}
|
}
|
||||||
cityInfo := result.([]interface{})
|
cityInfo := result.([]interface{})
|
||||||
if len(cityInfo) == 0 {
|
if len(cityInfo) == 0 {
|
||||||
@@ -57,14 +57,14 @@ func TestAccessJDQueryNoPage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessJDQueryHavePage(t *testing.T) {
|
func TestAccessAPIHavePage(t *testing.T) {
|
||||||
jdParams := map[string]interface{}{
|
jdParams := map[string]interface{}{
|
||||||
"pageNo": 1,
|
"pageNo": 1,
|
||||||
"pageSize": 20,
|
"pageSize": 20,
|
||||||
}
|
}
|
||||||
skuInfo, err := jdapi.AccessJDQueryHavePage("pms/querySkuInfos", jdParams, nil, []string{"skuName", "skuId"}, nil)
|
skuInfo, err := jdapi.AccessAPIHavePage("pms/querySkuInfos", jdParams, nil, []string{"skuName", "skuId"}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("AccessJDQueryHavePage return error:%v", err)
|
t.Fatalf("AccessAPIHavePage return error:%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(skuInfo) == 0 {
|
if len(skuInfo) == 0 {
|
||||||
@@ -79,12 +79,12 @@ func TestAccessJDQueryHavePage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenGetURL(t *testing.T) {
|
func TestGenerateURL(t *testing.T) {
|
||||||
params := make(map[string]interface{})
|
params := make(map[string]interface{})
|
||||||
params["key"] = "v"
|
params["key"] = "v"
|
||||||
params["key2"] = "v2"
|
params["key2"] = "v2"
|
||||||
|
|
||||||
fullURL := genGetURL(jdAPIURL, "address/allcities", params)
|
fullURL := generateURL(prodURL, "address/allcities", params)
|
||||||
|
|
||||||
response, err := http.Get(fullURL)
|
response, err := http.Get(fullURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
53
platformapi/jdapi/order.go
Normal file
53
platformapi/jdapi/order.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package jdapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrderStatusNew = "32000"
|
||||||
|
OrderStatusAdjust = "33080"
|
||||||
|
OrderStatusUserCancel = "20030"
|
||||||
|
OrderStatusWaitOutStore = "32001"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a API) OrderQuery(jdParams map[string]interface{}) (retVal []interface{}, err error) {
|
||||||
|
retVal, err = a.AccessAPIHavePage("order/es/query", jdParams, nil, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a API) QuerySingleOrder(orderId string) ([]interface{}, error) {
|
||||||
|
jdParams := make(map[string]interface{})
|
||||||
|
jdParams["orderId"] = orderId
|
||||||
|
return a.AccessAPIHavePage("order/es/query", jdParams, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a API) LegacyQuerySingleOrder(orderId string) (map[string]interface{}, error) {
|
||||||
|
jdParams := make(map[string]interface{})
|
||||||
|
jdParams["orderId"] = orderId
|
||||||
|
|
||||||
|
result, err := a.AccessAPI("order/es/query", jdParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr, _ := result["data"].(string)
|
||||||
|
var data map[string]interface{}
|
||||||
|
utils.UnmarshalUseNumber([]byte(dataStr), &data)
|
||||||
|
result["data"] = data
|
||||||
|
|
||||||
|
var dataResult map[string]interface{}
|
||||||
|
utils.UnmarshalUseNumber([]byte(data["result"].(string)), &dataResult)
|
||||||
|
data["result"] = dataResult
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a API) OrderAcceptOperate(orderId string, isAgreed bool) (interface{}, error) {
|
||||||
|
jdParams := map[string]interface{}{
|
||||||
|
"orderId": orderId,
|
||||||
|
"isAgreed": utils.Bool2String(isAgreed),
|
||||||
|
"operator": utils.GetAPIOperator(),
|
||||||
|
}
|
||||||
|
return a.AccessAPINoPage("ocs/orderAcceptOperate", jdParams, nil, nil)
|
||||||
|
}
|
||||||
@@ -7,41 +7,41 @@ import (
|
|||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MtpsCallbackResponse struct {
|
type CallbackResponse struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MtpsCallbackCommon struct {
|
type CallbackCommonMsg struct {
|
||||||
AppKey string
|
AppKey string
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
Sign string
|
Sign string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MtpsCallbackOrderMsg struct {
|
type CallbackOrderMsg struct {
|
||||||
MtpsOrderInfoCommon
|
OrderInfoCommon
|
||||||
MtpsCallbackCommon
|
CallbackCommonMsg
|
||||||
Status int
|
Status int
|
||||||
CancelReasonId int
|
CancelReasonId int
|
||||||
CancelReason string
|
CancelReason string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MtpsCallbackOrderExceptionMsg struct {
|
type CallbackOrderExceptionMsg struct {
|
||||||
MtpsOrderInfoCommon
|
OrderInfoCommon
|
||||||
MtpsCallbackCommon
|
CallbackCommonMsg
|
||||||
ExceptionId int64
|
ExceptionID int64
|
||||||
ExceptionCode int
|
ExceptionCode int
|
||||||
ExceptionDescr string
|
ExceptionDescr string
|
||||||
ExceptionTime int64
|
ExceptionTime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
SuccessResponse = &MtpsCallbackResponse{Code: 0}
|
SuccessResponse = &CallbackResponse{Code: 0}
|
||||||
SignatureIsNotOk = &MtpsCallbackResponse{Code: -1}
|
SignatureIsNotOk = &CallbackResponse{Code: -1}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *MTPSAPI) CheckCallbackValidation(request *http.Request) (callbackResponse *MtpsCallbackResponse) {
|
func (a *API) CheckCallbackValidation(request *http.Request) (callbackResponse *CallbackResponse) {
|
||||||
request.ParseForm()
|
request.ParseForm()
|
||||||
sign := m.signParams(request.PostForm)
|
sign := a.signParams(request.PostForm)
|
||||||
if sign != request.FormValue(signKey) {
|
if sign != request.FormValue(signKey) {
|
||||||
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, request.FormValue(signKey))
|
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, request.FormValue(signKey))
|
||||||
return SignatureIsNotOk
|
return SignatureIsNotOk
|
||||||
@@ -50,7 +50,7 @@ func (m *MTPSAPI) CheckCallbackValidation(request *http.Request) (callbackRespon
|
|||||||
for _, valueKey := range []string{"delivery_id", "mt_peisong_id", "order_id"} {
|
for _, valueKey := range []string{"delivery_id", "mt_peisong_id", "order_id"} {
|
||||||
baseapi.SugarLogger.Errorf("Missing mandatory param:%v", valueKey)
|
baseapi.SugarLogger.Errorf("Missing mandatory param:%v", valueKey)
|
||||||
if request.FormValue(valueKey) == "" {
|
if request.FormValue(valueKey) == "" {
|
||||||
return &MtpsCallbackResponse{
|
return &CallbackResponse{
|
||||||
Code: -1,
|
Code: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,19 +58,19 @@ func (m *MTPSAPI) CheckCallbackValidation(request *http.Request) (callbackRespon
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) GetOrderCallbackMsg(request *http.Request) (orderMsg *MtpsCallbackOrderMsg, callbackResponse *MtpsCallbackResponse) {
|
func (a *API) GetOrderCallbackMsg(request *http.Request) (orderMsg *CallbackOrderMsg, callbackResponse *CallbackResponse) {
|
||||||
if callbackResponse = m.CheckCallbackValidation(request); callbackResponse != nil {
|
if callbackResponse = a.CheckCallbackValidation(request); callbackResponse != nil {
|
||||||
return nil, callbackResponse
|
return nil, callbackResponse
|
||||||
}
|
}
|
||||||
orderMsg = &MtpsCallbackOrderMsg{
|
orderMsg = &CallbackOrderMsg{
|
||||||
MtpsOrderInfoCommon: MtpsOrderInfoCommon{
|
OrderInfoCommon: OrderInfoCommon{
|
||||||
DeliveryId: utils.Str2Int64(request.FormValue("delivery_id")),
|
DeliveryId: utils.Str2Int64(request.FormValue("delivery_id")),
|
||||||
MtPeisongId: request.FormValue("mt_peisong_id"),
|
MtPeisongId: request.FormValue("mt_peisong_id"),
|
||||||
OrderId: request.FormValue("order_id"),
|
OrderId: request.FormValue("order_id"),
|
||||||
CourierName: request.FormValue("courier_name"),
|
CourierName: request.FormValue("courier_name"),
|
||||||
CourierPhone: request.FormValue("courier_phone"),
|
CourierPhone: request.FormValue("courier_phone"),
|
||||||
},
|
},
|
||||||
MtpsCallbackCommon: MtpsCallbackCommon{
|
CallbackCommonMsg: CallbackCommonMsg{
|
||||||
AppKey: request.FormValue("appkey"),
|
AppKey: request.FormValue("appkey"),
|
||||||
Timestamp: utils.Str2Int64(request.FormValue("timestamp")),
|
Timestamp: utils.Str2Int64(request.FormValue("timestamp")),
|
||||||
Sign: request.FormValue("sign"),
|
Sign: request.FormValue("sign"),
|
||||||
@@ -82,24 +82,24 @@ func (m *MTPSAPI) GetOrderCallbackMsg(request *http.Request) (orderMsg *MtpsCall
|
|||||||
return orderMsg, nil
|
return orderMsg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) GetOrderExceptionCallbackMsg(request *http.Request) (orderMsg *MtpsCallbackOrderExceptionMsg, callbackResponse *MtpsCallbackResponse) {
|
func (a *API) GetOrderExceptionCallbackMsg(request *http.Request) (orderMsg *CallbackOrderExceptionMsg, callbackResponse *CallbackResponse) {
|
||||||
if callbackResponse = m.CheckCallbackValidation(request); callbackResponse != nil {
|
if callbackResponse = a.CheckCallbackValidation(request); callbackResponse != nil {
|
||||||
return nil, callbackResponse
|
return nil, callbackResponse
|
||||||
}
|
}
|
||||||
orderMsg = &MtpsCallbackOrderExceptionMsg{
|
orderMsg = &CallbackOrderExceptionMsg{
|
||||||
MtpsOrderInfoCommon: MtpsOrderInfoCommon{
|
OrderInfoCommon: OrderInfoCommon{
|
||||||
DeliveryId: utils.Str2Int64(request.FormValue("delivery_id")),
|
DeliveryId: utils.Str2Int64(request.FormValue("delivery_id")),
|
||||||
MtPeisongId: request.FormValue("mt_peisong_id"),
|
MtPeisongId: request.FormValue("mt_peisong_id"),
|
||||||
OrderId: request.FormValue("order_id"),
|
OrderId: request.FormValue("order_id"),
|
||||||
CourierName: request.FormValue("courier_name"),
|
CourierName: request.FormValue("courier_name"),
|
||||||
CourierPhone: request.FormValue("courier_phone"),
|
CourierPhone: request.FormValue("courier_phone"),
|
||||||
},
|
},
|
||||||
MtpsCallbackCommon: MtpsCallbackCommon{
|
CallbackCommonMsg: CallbackCommonMsg{
|
||||||
AppKey: request.FormValue("appkey"),
|
AppKey: request.FormValue("appkey"),
|
||||||
Timestamp: utils.Str2Int64(request.FormValue("timestamp")),
|
Timestamp: utils.Str2Int64(request.FormValue("timestamp")),
|
||||||
Sign: request.FormValue("sign"),
|
Sign: request.FormValue("sign"),
|
||||||
},
|
},
|
||||||
ExceptionId: utils.Str2Int64(request.FormValue("exception_id")),
|
ExceptionID: utils.Str2Int64(request.FormValue("exception_id")),
|
||||||
ExceptionCode: int(utils.Str2Int64(request.FormValue("exception_code"))),
|
ExceptionCode: int(utils.Str2Int64(request.FormValue("exception_code"))),
|
||||||
ExceptionDescr: request.FormValue("exception_descr"),
|
ExceptionDescr: request.FormValue("exception_descr"),
|
||||||
ExceptionTime: utils.Str2Int64(request.FormValue("exception_time")),
|
ExceptionTime: utils.Str2Int64(request.FormValue("exception_time")),
|
||||||
@@ -8,22 +8,14 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fatih/structs"
|
"github.com/fatih/structs"
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi"
|
"git.rosy.net.cn/baseapi"
|
||||||
"git.rosy.net.cn/baseapi/platform/common"
|
"git.rosy.net.cn/baseapi/platformapi"
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
clientTimeout = time.Second * 10
|
|
||||||
sleepSecondWhenLimited = 6 * time.Second
|
|
||||||
maxRetryCountWhenNetworkException = 3
|
|
||||||
maxRetryCountWhenReachLimited = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
mtpsAPIURL = "https://peisongopen.meituan.com/api"
|
mtpsAPIURL = "https://peisongopen.meituan.com/api"
|
||||||
signKey = "sign"
|
signKey = "sign"
|
||||||
@@ -38,9 +30,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DSCRapid = 4011
|
DeliveryServiceCodeRapid = 4011
|
||||||
DSCIntime = 4012
|
DeliveryServiceCodeIntime = 4012
|
||||||
DSCTogether = 4013
|
DeliveryServiceCodeTogether = 4013
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -78,7 +70,7 @@ const (
|
|||||||
CancelReasonRideerOther = 399
|
CancelReasonRideerOther = 399
|
||||||
)
|
)
|
||||||
|
|
||||||
type MtpsOrderInfoCommon struct {
|
type OrderInfoCommon struct {
|
||||||
DeliveryId int64
|
DeliveryId int64
|
||||||
MtPeisongId string
|
MtPeisongId string
|
||||||
OrderId string
|
OrderId string
|
||||||
@@ -86,30 +78,30 @@ type MtpsOrderInfoCommon struct {
|
|||||||
CourierPhone string
|
CourierPhone string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MtpsOrderInfo struct {
|
type OrderInfo struct {
|
||||||
MtpsOrderInfoCommon
|
OrderInfoCommon
|
||||||
Status int
|
Status int
|
||||||
OperateTime int
|
OperateTime int
|
||||||
CancelReasonId int
|
CancelReasonID int
|
||||||
CancelReason string
|
CancelReason string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MtpsOrderResponse struct {
|
type OrderResponse struct {
|
||||||
MtPeisongId string `json:"mt_peisong_id`
|
MtPeisongID string `json:"mt_peisong_id"`
|
||||||
DeliveryId int64 `json:"delivery_id`
|
DeliveryID int64 `json:"delivery_id"`
|
||||||
OrderId string `json:"order_id`
|
OrderID string `json:"order_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MTPSResult struct {
|
type ResponseResult struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Data map[string]interface{} `json:"data"`
|
Data map[string]interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MtpsCreateOrderByShopInfo struct {
|
type CreateOrderByShopParam struct {
|
||||||
DeliveryId int64 `json:"delivery_id"`
|
DeliveryID int64 `json:"delivery_id"`
|
||||||
OrderId string `json:"order_id"`
|
OrderID string `json:"order_id"`
|
||||||
ShopId string `json:"shop_id"`
|
ShopID string `json:"shop_id"`
|
||||||
DeliveryServiceCode int `json:"delivery_service_code"`
|
DeliveryServiceCode int `json:"delivery_service_code"`
|
||||||
ReceiverName string `json:"receiver_name"`
|
ReceiverName string `json:"receiver_name"`
|
||||||
ReceiverAddress string `json:"receiver_address"`
|
ReceiverAddress string `json:"receiver_address"`
|
||||||
@@ -123,23 +115,27 @@ type MtpsCreateOrderByShopInfo struct {
|
|||||||
OrderType int `json:"order_type"`
|
OrderType int `json:"order_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MTPSAPI struct {
|
type API struct {
|
||||||
appKey string
|
appKey string
|
||||||
secret string
|
secret string
|
||||||
client *http.Client
|
client *http.Client
|
||||||
|
config *platformapi.APIConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMTPSAPI(appKey, secret string) *MTPSAPI {
|
func New(appKey, secret string, config ...*platformapi.APIConfig) *API {
|
||||||
api := &MTPSAPI{
|
curConfig := platformapi.DefAPIConfig
|
||||||
|
if len(config) > 0 {
|
||||||
|
curConfig = *config[0]
|
||||||
|
}
|
||||||
|
return &API{
|
||||||
appKey: appKey,
|
appKey: appKey,
|
||||||
secret: secret,
|
secret: secret,
|
||||||
client: &http.Client{Timeout: clientTimeout},
|
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||||
|
config: &curConfig,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return api
|
func (a *API) signParams(params url.Values) string {
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MTPSAPI) signParams(params url.Values) string {
|
|
||||||
keys := make([]string, 0)
|
keys := make([]string, 0)
|
||||||
for k := range params {
|
for k := range params {
|
||||||
if k != signKey {
|
if k != signKey {
|
||||||
@@ -148,7 +144,7 @@ func (m *MTPSAPI) signParams(params url.Values) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
finalStr := m.secret
|
finalStr := a.secret
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
valStr := strings.Join(params[key], "")
|
valStr := strings.Join(params[key], "")
|
||||||
if valStr != "" {
|
if valStr != "" {
|
||||||
@@ -160,7 +156,7 @@ func (m *MTPSAPI) signParams(params url.Values) string {
|
|||||||
return fmt.Sprintf("%x", sha1.Sum([]byte(finalStr)))
|
return fmt.Sprintf("%x", sha1.Sum([]byte(finalStr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) AccessMTPS(action string, params map[string]interface{}) (retVal *MTPSResult, err error) {
|
func (a *API) AccessAPI(action string, params map[string]interface{}) (retVal *ResponseResult, err error) {
|
||||||
if params == nil {
|
if params == nil {
|
||||||
panic("params is nil!")
|
panic("params is nil!")
|
||||||
}
|
}
|
||||||
@@ -169,54 +165,47 @@ func (m *MTPSAPI) AccessMTPS(action string, params map[string]interface{}) (retV
|
|||||||
for k, v := range params {
|
for k, v := range params {
|
||||||
params2[k] = []string{fmt.Sprint(v)}
|
params2[k] = []string{fmt.Sprint(v)}
|
||||||
}
|
}
|
||||||
params2["appkey"] = []string{m.appKey}
|
params2["appkey"] = []string{a.appKey}
|
||||||
params2["timestamp"] = []string{utils.Int64ToStr(utils.GetCurTimestamp())}
|
params2["timestamp"] = []string{utils.Int64ToStr(utils.GetCurTimestamp())}
|
||||||
params2["version"] = []string{"1.0"}
|
params2["version"] = []string{"1.0"}
|
||||||
params2[signKey] = []string{m.signParams(params2)}
|
params2[signKey] = []string{a.signParams(params2)}
|
||||||
// baseapi.SugarLogger.Debug(params2.Encode())
|
// baseapi.SugarLogger.Debug(params2.Encode())
|
||||||
request, _ := http.NewRequest("POST", mtpsAPIURL+"/"+action, strings.NewReader(params2.Encode()))
|
request, _ := http.NewRequest("POST", mtpsAPIURL+"/"+action, strings.NewReader(params2.Encode()))
|
||||||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
apiAccess := &common.AccessPlatformAPIWithRetryParams{
|
|
||||||
MaxExceedLimitRetryCount: maxRetryCountWhenReachLimited,
|
|
||||||
MaxRecoverableRetryCount: maxRetryCountWhenNetworkException,
|
|
||||||
SleepSecondWhenExceedLimit: sleepSecondWhenLimited,
|
|
||||||
Client: m.client,
|
|
||||||
Request: request,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = common.AccessPlatformAPIWithRetry(apiAccess, func(response *http.Response) (result string, err error) {
|
err = platformapi.AccessPlatformAPIWithRetry(a.client, request, a.config, func(response *http.Response) (result string, err error) {
|
||||||
jsonResult1, err := utils.HttpResponse2Json(response)
|
jsonResult1, err := utils.HTTPResponse2Json(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
baseapi.SugarLogger.Warnf("HttpResponse2Json return:%v", err)
|
return platformapi.ErrLevelGeneralFail, platformapi.ErrResponseDataFormatWrong
|
||||||
return common.PAErrorLevelGeneralFail, err
|
|
||||||
}
|
}
|
||||||
code := int(utils.MustInterface2Int64(jsonResult1["code"]))
|
code := int(utils.MustInterface2Int64(jsonResult1["code"]))
|
||||||
retVal = &MTPSResult{
|
retVal = &ResponseResult{
|
||||||
Code: code,
|
Code: code,
|
||||||
}
|
}
|
||||||
if code == ResponseCodeSuccess {
|
if code == ResponseCodeSuccess {
|
||||||
if innerData, ok := jsonResult1["data"]; ok {
|
if innerData, ok := jsonResult1["data"]; ok {
|
||||||
retVal.Data, _ = innerData.(map[string]interface{})
|
retVal.Data, _ = innerData.(map[string]interface{})
|
||||||
}
|
}
|
||||||
return common.PAErrorLevelSuccess, nil
|
return platformapi.ErrLevelSuccess, nil
|
||||||
}
|
}
|
||||||
baseapi.SugarLogger.Debug(jsonResult1)
|
baseapi.SugarLogger.Warnf("response business code is not ok, data:%v, code:%v", jsonResult1, code)
|
||||||
retVal.Message = jsonResult1["message"].(string)
|
retVal.Message = jsonResult1["message"].(string)
|
||||||
return common.PAErrorLevelGeneralFail, utils.NewErrorIntCode(retVal.Message, code)
|
newErr := utils.NewErrorIntCode(retVal.Message, code)
|
||||||
|
return platformapi.ErrLevelCodeIsNotOK, newErr
|
||||||
})
|
})
|
||||||
|
|
||||||
return retVal, err
|
return retVal, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) result2OrderResponse(result *MTPSResult) (order *MtpsOrderResponse) {
|
func (a *API) result2OrderResponse(result *ResponseResult) (order *OrderResponse) {
|
||||||
order = new(MtpsOrderResponse)
|
order = new(OrderResponse)
|
||||||
order.MtPeisongId = result.Data["mt_peisong_id"].(string)
|
order.MtPeisongID = result.Data["mt_peisong_id"].(string)
|
||||||
order.DeliveryId = utils.MustInterface2Int64(result.Data["delivery_id"])
|
order.DeliveryID = utils.MustInterface2Int64(result.Data["delivery_id"])
|
||||||
order.OrderId = result.Data["order_id"].(string)
|
order.OrderID = result.Data["order_id"].(string)
|
||||||
return order
|
return order
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) CreateOrderByShop(basicParams *MtpsCreateOrderByShopInfo, addParams map[string]interface{}) (order *MtpsOrderResponse, err error) {
|
func (a *API) CreateOrderByShop(basicParams *CreateOrderByShopParam, addParams map[string]interface{}) (order *OrderResponse, err error) {
|
||||||
params := structs.Map(basicParams)
|
params := structs.Map(basicParams)
|
||||||
params["goods_value"] = strconv.FormatFloat(basicParams.GoodsValue, 'f', 2, 64)
|
params["goods_value"] = strconv.FormatFloat(basicParams.GoodsValue, 'f', 2, 64)
|
||||||
params["goods_weight"] = strconv.FormatFloat(basicParams.GoodsWeight, 'f', 2, 64)
|
params["goods_weight"] = strconv.FormatFloat(basicParams.GoodsWeight, 'f', 2, 64)
|
||||||
@@ -225,67 +214,66 @@ func (m *MTPSAPI) CreateOrderByShop(basicParams *MtpsCreateOrderByShopInfo, addP
|
|||||||
if params["order_type"] != utils.Int2Str(OrderTypeBook) {
|
if params["order_type"] != utils.Int2Str(OrderTypeBook) {
|
||||||
delete(params, "expected_delivery_time")
|
delete(params, "expected_delivery_time")
|
||||||
}
|
}
|
||||||
if result, err := m.AccessMTPS("order/createByShop", allParams); err != nil {
|
if result, err := a.AccessAPI("order/createByShop", allParams); err != nil {
|
||||||
baseapi.SugarLogger.Debugf("result:%v", result)
|
return nil, err
|
||||||
return nil, utils.NewErrorIntCode(err.Error(), result.Code)
|
|
||||||
} else {
|
} else {
|
||||||
return m.result2OrderResponse(result), nil
|
return a.result2OrderResponse(result), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) QueryOrderStatus(deliveryId int64, mtPeiSongId string) (retVal map[string]interface{}, err error) {
|
func (a *API) QueryOrderStatus(deliveryId int64, mtPeiSongId string) (retVal map[string]interface{}, err error) {
|
||||||
params := map[string]interface{}{
|
params := map[string]interface{}{
|
||||||
"delivery_id": deliveryId,
|
"delivery_id": deliveryId,
|
||||||
"mt_peisong_id": mtPeiSongId,
|
"mt_peisong_id": mtPeiSongId,
|
||||||
}
|
}
|
||||||
if result, err := m.AccessMTPS("order/status/query", params); err != nil {
|
if result, err := a.AccessAPI("order/status/query", params); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
return result.Data, nil
|
return result.Data, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) CancelOrder(deliveryId int64, mtPeiSongId string, cancelReasonId int, cancelReason string) (result *MtpsOrderResponse, err error) {
|
func (a *API) CancelOrder(deliveryId int64, mtPeiSongId string, cancelReasonId int, cancelReason string) (result *OrderResponse, err error) {
|
||||||
params := map[string]interface{}{
|
params := map[string]interface{}{
|
||||||
"delivery_id": deliveryId,
|
"delivery_id": deliveryId,
|
||||||
"mt_peisong_id": mtPeiSongId,
|
"mt_peisong_id": mtPeiSongId,
|
||||||
"cancel_reason_id": cancelReasonId,
|
"cancel_reason_id": cancelReasonId,
|
||||||
"cancel_reason": cancelReason,
|
"cancel_reason": cancelReason,
|
||||||
}
|
}
|
||||||
if result, err := m.AccessMTPS("order/delete", params); err != nil {
|
if result, err := a.AccessAPI("order/delete", params); err != nil {
|
||||||
baseapi.SugarLogger.Debugf("result:%v", result)
|
baseapi.SugarLogger.Debugf("result:%v", result)
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
return m.result2OrderResponse(result), nil
|
return a.result2OrderResponse(result), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) simulateOrderBehavior(action string, deliveryId int64, mtPeiSongId string) (err error) {
|
func (a *API) simulateOrderBehavior(action string, deliveryId int64, mtPeiSongId string) (err error) {
|
||||||
params := map[string]interface{}{
|
params := map[string]interface{}{
|
||||||
"delivery_id": deliveryId,
|
"delivery_id": deliveryId,
|
||||||
"mt_peisong_id": mtPeiSongId,
|
"mt_peisong_id": mtPeiSongId,
|
||||||
}
|
}
|
||||||
_, err = m.AccessMTPS("test/order/"+action, params)
|
_, err = a.AccessAPI("test/order/"+action, params)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) SimulateArrange(deliveryId int64, mtPeiSongId string) (err error) {
|
func (a *API) SimulateArrange(deliveryId int64, mtPeiSongId string) (err error) {
|
||||||
return m.simulateOrderBehavior("arrange", deliveryId, mtPeiSongId)
|
return a.simulateOrderBehavior("arrange", deliveryId, mtPeiSongId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) SimulatePickup(deliveryId int64, mtPeiSongId string) (err error) {
|
func (a *API) SimulatePickup(deliveryId int64, mtPeiSongId string) (err error) {
|
||||||
return m.simulateOrderBehavior("pickup", deliveryId, mtPeiSongId)
|
return a.simulateOrderBehavior("pickup", deliveryId, mtPeiSongId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) SimulateDeliver(deliveryId int64, mtPeiSongId string) (err error) {
|
func (a *API) SimulateDeliver(deliveryId int64, mtPeiSongId string) (err error) {
|
||||||
return m.simulateOrderBehavior("deliver", deliveryId, mtPeiSongId)
|
return a.simulateOrderBehavior("deliver", deliveryId, mtPeiSongId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) SimulateRearrange(deliveryId int64, mtPeiSongId string) (err error) {
|
func (a *API) SimulateRearrange(deliveryId int64, mtPeiSongId string) (err error) {
|
||||||
return m.simulateOrderBehavior("rearrange", deliveryId, mtPeiSongId)
|
return a.simulateOrderBehavior("rearrange", deliveryId, mtPeiSongId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MTPSAPI) SimulateReportException(deliveryId int64, mtPeiSongId string) (err error) {
|
func (a *API) SimulateReportException(deliveryId int64, mtPeiSongId string) (err error) {
|
||||||
return m.simulateOrderBehavior("reportException", deliveryId, mtPeiSongId)
|
return a.simulateOrderBehavior("reportException", deliveryId, mtPeiSongId)
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mtpsapi *MTPSAPI
|
mtpsapi *API
|
||||||
sugarLogger *zap.SugaredLogger
|
sugarLogger *zap.SugaredLogger
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,8 +18,8 @@ func init() {
|
|||||||
logger, _ := zap.NewDevelopment()
|
logger, _ := zap.NewDevelopment()
|
||||||
sugarLogger = logger.Sugar()
|
sugarLogger = logger.Sugar()
|
||||||
baseapi.Init(sugarLogger)
|
baseapi.Init(sugarLogger)
|
||||||
mtpsapi = NewMTPSAPI("25e816550bc9484480642f19a95f13fd", "r4$HqrKx9~=7?2Jfo,$Z~a7%~k!Au&pEdI2)oPJvSbH2ao@2N0[8wSIvtuumh_J^")
|
mtpsapi = New("25e816550bc9484480642f19a95f13fd", "r4$HqrKx9~=7?2Jfo,$Z~a7%~k!Au&pEdI2)oPJvSbH2ao@2N0[8wSIvtuumh_J^")
|
||||||
// mtpsapi = NewMTPSAPI("3c0a05d464c247c19d7ec13accc78605", "b1M}9?:sTbsB[OF2gNORnN(|(iy9rB8(`7]|[wGLnbmt`evfM>E:A90DjHAW:UPE")
|
// mtpsapi = New("3c0a05d464c247c19d7ec13accc78605", "b1M}9?:sTbsB[OF2gNORnN(|(iy9rB8(`7]|[wGLnbmt`evfM>E:A90DjHAW:UPE")
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleError(t *testing.T, err error) {
|
func handleError(t *testing.T, err error) {
|
||||||
@@ -32,15 +32,15 @@ func TestTest(t *testing.T) {
|
|||||||
sugarLogger.Debug(utils.GetCurTimeStr())
|
sugarLogger.Debug(utils.GetCurTimeStr())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessMTPS(t *testing.T) {
|
func TestAccessAPI(t *testing.T) {
|
||||||
mtPeiSongId := "1529387562097059"
|
mtPeiSongId := "1529387562097059"
|
||||||
params := map[string]interface{}{
|
params := map[string]interface{}{
|
||||||
"delivery_id": 123456789,
|
"delivery_id": 123456789,
|
||||||
"mt_peisong_id": mtPeiSongId,
|
"mt_peisong_id": mtPeiSongId,
|
||||||
}
|
}
|
||||||
result, err := mtpsapi.AccessMTPS("order/status/query", params)
|
result, err := mtpsapi.AccessAPI("order/status/query", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error when accessing AccessMTPS result:%v, error:%v", result, err)
|
t.Fatalf("Error when accessing AccessAPI result:%v, error:%v", result, err)
|
||||||
} else {
|
} else {
|
||||||
getMtPsId := result.Data["mt_peisong_id"].(string)
|
getMtPsId := result.Data["mt_peisong_id"].(string)
|
||||||
if getMtPsId != mtPeiSongId {
|
if getMtPsId != mtPeiSongId {
|
||||||
@@ -50,12 +50,12 @@ func TestAccessMTPS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateOrderByShop(t *testing.T) {
|
func TestCreateOrderByShop(t *testing.T) {
|
||||||
basicParams := &MtpsCreateOrderByShopInfo{
|
basicParams := &CreateOrderByShopParam{
|
||||||
DeliveryId: 123456789,
|
DeliveryID: 123456789,
|
||||||
OrderId: "order_123456789",
|
OrderID: "order_123456789",
|
||||||
// 设置测试门店 id,测试门店的坐标地址为 97235456,31065079(高德坐标),配送范围3km
|
// 设置测试门店 id,测试门店的坐标地址为 97235456,31065079(高德坐标),配送范围3km
|
||||||
ShopId: "test_0001",
|
ShopID: "test_0001",
|
||||||
DeliveryServiceCode: DSCIntime,
|
DeliveryServiceCode: DeliveryServiceCodeIntime,
|
||||||
ReceiverName: "xjh",
|
ReceiverName: "xjh",
|
||||||
ReceiverAddress: "九里堤",
|
ReceiverAddress: "九里堤",
|
||||||
ReceiverPhone: "18112345678",
|
ReceiverPhone: "18112345678",
|
||||||
119
platformapi/platformapi.go
Normal file
119
platformapi/platformapi.go
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
package platformapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatih/structs"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefClientTimeout = 10 * time.Second
|
||||||
|
DefSleepSecondWhenExceedLimit = 6 * time.Second
|
||||||
|
DefMaxRecoverableRetryCount = 3
|
||||||
|
DefMaxExceedLimitRetryCount = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
type APIRetryConfig struct {
|
||||||
|
MaxExceedLimitRetryCount int
|
||||||
|
MaxRecoverableRetryCount int
|
||||||
|
SleepSecondWhenExceedLimit time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type APIConfig struct {
|
||||||
|
APIRetryConfig
|
||||||
|
ClientTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessPlatformAPIWithRetryParam struct {
|
||||||
|
APIRetryConfig
|
||||||
|
Client *http.Client
|
||||||
|
Request *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefAPIConfig = APIConfig{
|
||||||
|
APIRetryConfig: APIRetryConfig{
|
||||||
|
MaxExceedLimitRetryCount: DefMaxExceedLimitRetryCount,
|
||||||
|
MaxRecoverableRetryCount: DefMaxRecoverableRetryCount,
|
||||||
|
SleepSecondWhenExceedLimit: DefSleepSecondWhenExceedLimit,
|
||||||
|
},
|
||||||
|
ClientTimeout: DefClientTimeout,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrLevelSuccess = "JXC4_SUCCESS"
|
||||||
|
ErrLevelExceedLimit = "JXC4_EXCEED_LIMIT"
|
||||||
|
ErrLevelRecoverableErr = "JXC4_RECOVERABLE"
|
||||||
|
ErrLevelGeneralFail = "JXC4_GENERAL_FAIL"
|
||||||
|
ErrLevelCodeIsNotOK = "JXC4_CODE_IS_NOT_OK"
|
||||||
|
)
|
||||||
|
|
||||||
|
// common api access error
|
||||||
|
var (
|
||||||
|
ErrAPIAccessFailed = errors.New("access API failed")
|
||||||
|
ErrHTTPCodeIsNot200 = errors.New("HTTP code is not 200")
|
||||||
|
ErrRecoverableErrReachMaxRetry = errors.New("recoverable error reach max retry count")
|
||||||
|
ErrLimitExceedReachMaxRetry = errors.New("limit exceed reach max retry count")
|
||||||
|
ErrResponseDataFormatWrong = errors.New("the data of response has wrong format")
|
||||||
|
)
|
||||||
|
|
||||||
|
// common callback response
|
||||||
|
var (
|
||||||
|
ErrStrUnescapeError = "can not unescape data:%v, error:%v"
|
||||||
|
ErrStrUnmarshalError = "can not unmarshal data:%v, error:%v"
|
||||||
|
ErrStrCallbackSignatureIsWrong = "wrong signature"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
structs.DefaultTagName = "json"
|
||||||
|
}
|
||||||
|
|
||||||
|
func AccessPlatformAPIWithRetry(client *http.Client, request *http.Request, config *APIConfig, handleResponse func(response *http.Response) (string, error)) error {
|
||||||
|
exceedLimitRetryCount := 0
|
||||||
|
recoverableErrorRetryCount := 0
|
||||||
|
for {
|
||||||
|
response, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
baseapi.SugarLogger.Debugf("client.Get return err:%v", err)
|
||||||
|
err, ok := err.(net.Error)
|
||||||
|
recoverableErrorRetryCount++
|
||||||
|
if ok && err.Timeout() && recoverableErrorRetryCount <= config.MaxRecoverableRetryCount {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
baseapi.SugarLogger.Errorf("access api error:%v", err)
|
||||||
|
return ErrAPIAccessFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
if response.StatusCode != 200 {
|
||||||
|
baseapi.SugarLogger.Errorf("HTTP code not 200, it's:%v", response.StatusCode)
|
||||||
|
return ErrHTTPCodeIsNot200
|
||||||
|
}
|
||||||
|
|
||||||
|
errLevel, err := handleResponse(response)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
} else if errLevel == ErrLevelExceedLimit {
|
||||||
|
exceedLimitRetryCount++
|
||||||
|
if exceedLimitRetryCount <= config.MaxExceedLimitRetryCount {
|
||||||
|
time.Sleep(config.SleepSecondWhenExceedLimit)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
return ErrLimitExceedReachMaxRetry
|
||||||
|
}
|
||||||
|
} else if errLevel == ErrLevelRecoverableErr {
|
||||||
|
recoverableErrorRetryCount++
|
||||||
|
if recoverableErrorRetryCount <= config.MaxRecoverableRetryCount {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,31 +2,43 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrorWithCode struct {
|
type ErrorWithCode struct {
|
||||||
|
level int
|
||||||
str string
|
str string
|
||||||
code string
|
code string
|
||||||
intCode int
|
intCode int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewErrorCode(err, code string) *ErrorWithCode {
|
func NewErrorCode(err, code string, level ...int) *ErrorWithCode {
|
||||||
return &ErrorWithCode{
|
retVal := &ErrorWithCode{
|
||||||
str: err,
|
str: err,
|
||||||
code: code,
|
code: code,
|
||||||
intCode: Str2Int(code),
|
|
||||||
}
|
}
|
||||||
|
retVal.intCode, _ = strconv.Atoi(code)
|
||||||
|
if len(level) > 0 {
|
||||||
|
retVal.level = level[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewErrorIntCode(err string, code int) *ErrorWithCode {
|
return retVal
|
||||||
return &ErrorWithCode{
|
|
||||||
str: err,
|
|
||||||
code: Int2Str(code),
|
|
||||||
intCode: code,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewErrorIntCode(err string, code int, level ...int) *ErrorWithCode {
|
||||||
|
return NewErrorCode(err, Int2Str(code), level...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorWithCode) Error() string {
|
func (e *ErrorWithCode) Error() string {
|
||||||
return fmt.Sprintf("%s, code:%s", e.str, e.code)
|
return fmt.Sprintf("level:%d, str:%s, code:%s", e.level, e.str, e.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrorWithCode) String() string {
|
||||||
|
return e.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrorWithCode) Level() int {
|
||||||
|
return e.level
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrorWithCode) Code() string {
|
func (e *ErrorWithCode) Code() string {
|
||||||
|
|||||||
@@ -92,7 +92,11 @@ func DictKeysMan(data interface{}, keysToRemove []string, keysToKeep []string) i
|
|||||||
func UnmarshalUseNumber(data []byte, result interface{}) error {
|
func UnmarshalUseNumber(data []byte, result interface{}) error {
|
||||||
d := json.NewDecoder(bytes.NewReader(data))
|
d := json.NewDecoder(bytes.NewReader(data))
|
||||||
d.UseNumber()
|
d.UseNumber()
|
||||||
return d.Decode(result)
|
err := d.Decode(result)
|
||||||
|
if err != nil {
|
||||||
|
baseapi.SugarLogger.Errorf("decode data:%v, error:%v", string(data), err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustMarshal(obj interface{}) []byte {
|
func MustMarshal(obj interface{}) []byte {
|
||||||
@@ -112,12 +116,18 @@ func Bool2String(value bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Str2Int(str string) int {
|
func Str2Int(str string) int {
|
||||||
retVal, _ := strconv.Atoi(str)
|
retVal, err := strconv.Atoi(str)
|
||||||
|
if err != nil {
|
||||||
|
baseapi.SugarLogger.Errorf("error when convert %s to int", str)
|
||||||
|
}
|
||||||
return retVal
|
return retVal
|
||||||
}
|
}
|
||||||
|
|
||||||
func Str2Int64(str string) int64 {
|
func Str2Int64(str string) int64 {
|
||||||
retVal, _ := strconv.ParseInt(str, 10, 64)
|
retVal, err := strconv.ParseInt(str, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
baseapi.SugarLogger.Errorf("error when convert %s to int64", str)
|
||||||
|
}
|
||||||
return retVal
|
return retVal
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,15 +160,15 @@ func Timestamp2Str(timestamp int64) string {
|
|||||||
return time.Unix(timestamp/1000, 0).Format("2006-01-02 15:04:05")
|
return time.Unix(timestamp/1000, 0).Format("2006-01-02 15:04:05")
|
||||||
}
|
}
|
||||||
|
|
||||||
func HttpResponse2Json(response *http.Response) (map[string]interface{}, error) {
|
func HTTPResponse2Json(response *http.Response) (map[string]interface{}, error) {
|
||||||
var jsonResult map[string]interface{}
|
var jsonResult map[string]interface{}
|
||||||
bodyData, err := ioutil.ReadAll(response.Body)
|
bodyData, err := ioutil.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
baseapi.SugarLogger.Errorf("ioutil.ReadAll error:%v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = UnmarshalUseNumber(bodyData, &jsonResult)
|
if err = UnmarshalUseNumber(bodyData, &jsonResult); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return jsonResult, nil
|
return jsonResult, nil
|
||||||
|
|||||||
@@ -73,4 +73,7 @@ func TestJson(t *testing.T) {
|
|||||||
unmarshStr(t, jsonStr, &obj2)
|
unmarshStr(t, jsonStr, &obj2)
|
||||||
unmarshStr(t, jsonStr, &obj3)
|
unmarshStr(t, jsonStr, &obj3)
|
||||||
unmarshStr(t, jsonStr, &obj4)
|
unmarshStr(t, jsonStr, &obj4)
|
||||||
|
t.Skip("skip the flollowing")
|
||||||
|
t.Fatal(1)
|
||||||
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user