Merge branch 'master' of e.coding.net:rosydev/baseapi
This commit is contained in:
@@ -43,6 +43,7 @@ const (
|
||||
|
||||
const (
|
||||
FakeDistrictPadding = 9000000
|
||||
MaxConvertCount = 40
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -89,6 +90,11 @@ type District struct {
|
||||
Districts []*District `json:"districts"`
|
||||
}
|
||||
|
||||
type Coordinate struct {
|
||||
Lng float64 `json:"lng"`
|
||||
Lat float64 `json:"lat"`
|
||||
}
|
||||
|
||||
type ResponseResult map[string]interface{}
|
||||
|
||||
type API struct {
|
||||
@@ -127,6 +133,10 @@ func (a *API) signParams(mapData map[string]interface{}) string {
|
||||
return fmt.Sprintf("%X", md5.Sum([]byte(finalStr)))
|
||||
}
|
||||
|
||||
func coordinate2String(lng, lat float64) (str string) {
|
||||
return fmt.Sprintf("%.6f,%.6f", lng, lat)
|
||||
}
|
||||
|
||||
func (a *API) AccessAPI(apiStr string, params map[string]interface{}) (retVal ResponseResult, err error) {
|
||||
params2 := utils.MergeMaps(utils.Params2Map("key", a.key, "output", "json"), params)
|
||||
params2[signKey] = a.signParams(params2)
|
||||
@@ -161,6 +171,15 @@ func (a *API) AccessAPI(apiStr string, params map[string]interface{}) (retVal Re
|
||||
|
||||
// 为了方便调用者编码,如果失败,也会返回未转换的原始值
|
||||
func (a *API) CoordinateConvert(lng, lat float64, coordsys string) (retLng, retLat float64, err error) {
|
||||
// outCoords, err := a.BatchCoordinateConvert([]*Coordinate{
|
||||
// &Coordinate{
|
||||
// Lng: lng,
|
||||
// Lat: lat,
|
||||
// },
|
||||
// }, coordsys)
|
||||
// if err == nil {
|
||||
// retLng, retLat = outCoords[0].Lng, outCoords[0].Lat
|
||||
// }
|
||||
if coordsys == "" || coordsys == CoordSysAutonavi {
|
||||
return lng, lat, nil
|
||||
}
|
||||
@@ -168,7 +187,7 @@ func (a *API) CoordinateConvert(lng, lat float64, coordsys string) (retLng, retL
|
||||
return 0.0, 0.0, nil
|
||||
}
|
||||
params := map[string]interface{}{
|
||||
"locations": fmt.Sprintf("%.6f,%.6f", lng, lat),
|
||||
"locations": coordinate2String(lng, lat),
|
||||
"coordsys": coordsys,
|
||||
}
|
||||
result, err := a.AccessAPI("assistant/coordinate/convert", params)
|
||||
@@ -180,6 +199,33 @@ func (a *API) CoordinateConvert(lng, lat float64, coordsys string) (retLng, retL
|
||||
return lng, lat, err
|
||||
}
|
||||
|
||||
func (a *API) BatchCoordinateConvert(coords []*Coordinate, coordsys string) (outCoords []*Coordinate, err error) {
|
||||
if coordsys == "" || coordsys == CoordSysAutonavi {
|
||||
return coords, nil
|
||||
}
|
||||
var coordsStrList []string
|
||||
for _, v := range coords {
|
||||
coordsStrList = append(coordsStrList, coordinate2String(v.Lng, v.Lat))
|
||||
}
|
||||
params := map[string]interface{}{
|
||||
"locations": strings.Join(coordsStrList, "|"),
|
||||
"coordsys": coordsys,
|
||||
}
|
||||
result, err := a.AccessAPI("assistant/coordinate/convert", params)
|
||||
if err == nil {
|
||||
coordinate := result["locations"].(string)
|
||||
retCoordsStrList := strings.Split(coordinate, ";")
|
||||
for _, v := range retCoordsStrList {
|
||||
pair := strings.Split(v, ",")
|
||||
outCoords = append(outCoords, &Coordinate{
|
||||
Lng: utils.Str2Float64(pair[0]),
|
||||
Lat: utils.Str2Float64(pair[1]),
|
||||
})
|
||||
}
|
||||
}
|
||||
return outCoords, err
|
||||
}
|
||||
|
||||
func (a *API) GetCoordinateFromAddress(address string, cityInfo string) (lng, lat float64, districtCode int) {
|
||||
params := map[string]interface{}{
|
||||
"address": address,
|
||||
@@ -218,7 +264,7 @@ func (a *API) GetCoordinateDistrictCode(lng, lat float64) (districtCode int) {
|
||||
|
||||
func (a *API) GetCoordinateAreaInfo(lng, lat float64) (areaInfo map[string]interface{}, err error) {
|
||||
params := map[string]interface{}{
|
||||
"location": fmt.Sprintf("%.6f,%.6f", lng, lat),
|
||||
"location": coordinate2String(lng, lat),
|
||||
}
|
||||
result, err := a.AccessAPI("geocode/regeo", params)
|
||||
return result, err
|
||||
@@ -283,3 +329,18 @@ func (a *API) getDistrictsFromInterface(districts interface{}) (districtList []*
|
||||
func GetDistrictLevel(levelName string) (level int) {
|
||||
return levelStr2IntMap[levelName]
|
||||
}
|
||||
|
||||
// 两点之间的步行距离,单位为米
|
||||
func (a *API) WalkingDistance(lng1, lat1, lng2, lat2 float64) (distance float64) {
|
||||
params := map[string]interface{}{
|
||||
"origin": coordinate2String(lng1, lat1),
|
||||
"destination": coordinate2String(lng2, lat2),
|
||||
}
|
||||
result, err := a.AccessAPI("direction/walking", params)
|
||||
if err == nil {
|
||||
if paths, _ := result["route"].(map[string]interface{})["paths"].([]interface{}); len(paths) > 0 {
|
||||
distance = utils.Interface2Float64WithDefault(paths[0].(map[string]interface{})["distance"], 0)
|
||||
}
|
||||
}
|
||||
return distance
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func init() {
|
||||
sugarLogger = logger.Sugar()
|
||||
baseapi.Init(sugarLogger)
|
||||
|
||||
autonaviAPI = New("4427170f870af2110becb8852d36ab08")
|
||||
autonaviAPI = New("ef64f638f31e05cb7bde28790f7309fe")
|
||||
}
|
||||
|
||||
func TestCoordinateConvert(t *testing.T) {
|
||||
@@ -88,3 +88,8 @@ func TestGetCoordinateFromAddress(t *testing.T) {
|
||||
lng, lat, districtCode := autonaviAPI.GetCoordinateFromAddress("天府广场", "成都市")
|
||||
t.Logf("lng:%f, lat:%f, districtCode:%d", lng, lat, districtCode)
|
||||
}
|
||||
|
||||
func TestWalkingDistance(t *testing.T) {
|
||||
distance := autonaviAPI.WalkingDistance(104.057289, 30.694798, 104.066289, 30.695598)
|
||||
t.Logf("distance:%f", distance)
|
||||
}
|
||||
|
||||
168
platformapi/baidunavi/baidunavi.go
Normal file
168
platformapi/baidunavi/baidunavi.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package baidunavi
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
signKey = "sn"
|
||||
resultKey = "result"
|
||||
prodURL = "http://api.map.baidu.com"
|
||||
)
|
||||
|
||||
const (
|
||||
StatusCodeSuccess = 0
|
||||
StatusCodeInternalErr = 1 // 服务器内部错误
|
||||
StatusCodeExceedDailyQuota = 301 // 永久配额超限,限制访问
|
||||
StatusCodeExceedQuota = 302 // 天配额超限,限制访问
|
||||
StatusCodeExceedDailyConcurrentQuota = 401 // 当前并发量已经超过约定并发配额,限制访问
|
||||
StatusCodeExceedConcurrentQuota = 402 // 当前并发量已经超过约定并发配额,并且服务总并发量也已经超过设定的总并发配额,限制访问
|
||||
)
|
||||
|
||||
const (
|
||||
CoordSysWGS84 = 1 // GPS设备获取的角度坐标,WGS84坐标
|
||||
CoordSysGCJ02 = 3 // google地图、soso地图、aliyun地图、mapabc地图和amap地图所用坐标,国测局(GCJ02)坐标
|
||||
CoordSysBaiDu = 5 // 百度地图采用的经纬度坐标
|
||||
)
|
||||
|
||||
const (
|
||||
MaxCoordsConvBatchSize = 100
|
||||
)
|
||||
|
||||
var (
|
||||
exceedLimitCodes = map[int]int{
|
||||
StatusCodeExceedDailyQuota: 1,
|
||||
StatusCodeExceedQuota: 1,
|
||||
StatusCodeExceedDailyConcurrentQuota: 1,
|
||||
StatusCodeExceedConcurrentQuota: 1,
|
||||
}
|
||||
|
||||
canRetryCodes = map[int]int{
|
||||
StatusCodeInternalErr: 1,
|
||||
}
|
||||
)
|
||||
|
||||
type Coordinate struct {
|
||||
Lng float64 `json:"x"`
|
||||
Lat float64 `json:"y"`
|
||||
}
|
||||
|
||||
type API struct {
|
||||
client *http.Client
|
||||
config *platformapi.APIConfig
|
||||
ak string
|
||||
sk string
|
||||
}
|
||||
|
||||
func New(ak, sk string, config ...*platformapi.APIConfig) *API {
|
||||
curConfig := platformapi.DefAPIConfig
|
||||
if len(config) > 0 {
|
||||
curConfig = *config[0]
|
||||
}
|
||||
return &API{
|
||||
ak: ak,
|
||||
sk: sk,
|
||||
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||
config: &curConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *API) signParams(apiStr string, mapData map[string]interface{}) string {
|
||||
keys := make([]string, 0)
|
||||
for k := range mapData {
|
||||
if k != signKey {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
strList := []string{}
|
||||
for _, k := range keys {
|
||||
strList = append(strList, k+"="+url.QueryEscape(fmt.Sprint(mapData[k])))
|
||||
}
|
||||
finalStr := "/" + apiStr + "?" + strings.Join(strList, "&") + a.sk
|
||||
// baseapi.SugarLogger.Debugf("sign str:%v", finalStr)
|
||||
finalStr = url.QueryEscape(finalStr)
|
||||
return fmt.Sprintf("%x", md5.Sum([]byte(finalStr)))
|
||||
}
|
||||
|
||||
func genGetURL(baseURL, apiStr string, params map[string]interface{}) string {
|
||||
keys := make([]string, 0)
|
||||
for k := range params {
|
||||
if k != signKey {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
strList := []string{}
|
||||
for _, k := range keys {
|
||||
strList = append(strList, k+"="+url.QueryEscape(fmt.Sprint(params[k])))
|
||||
}
|
||||
strList = append(strList, signKey+"="+url.QueryEscape(fmt.Sprint(params[signKey])))
|
||||
queryString := "?" + strings.Join(strList, "&")
|
||||
if apiStr != "" {
|
||||
return baseURL + "/" + apiStr + queryString
|
||||
}
|
||||
return baseURL + queryString
|
||||
}
|
||||
|
||||
func (a *API) AccessAPI(apiStr string, params map[string]interface{}) (retVal interface{}, err error) {
|
||||
apiStr += "/"
|
||||
params2 := utils.MergeMaps(utils.Params2Map("ak", a.ak, "output", "json"), params)
|
||||
params2[signKey] = a.signParams(apiStr, params2)
|
||||
|
||||
err = platformapi.AccessPlatformAPIWithRetry(a.client,
|
||||
func() *http.Request {
|
||||
request, _ := http.NewRequest(http.MethodGet, genGetURL(prodURL, apiStr, params2), nil)
|
||||
return request
|
||||
},
|
||||
a.config,
|
||||
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
|
||||
if jsonResult1 == nil {
|
||||
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
|
||||
}
|
||||
status := int(utils.MustInterface2Int64(jsonResult1["status"]))
|
||||
if status == StatusCodeSuccess {
|
||||
retVal = jsonResult1[resultKey]
|
||||
return platformapi.ErrLevelSuccess, nil
|
||||
}
|
||||
newErr := utils.NewErrorIntCode(utils.Interface2String(jsonResult1["message"]), status)
|
||||
if _, ok := exceedLimitCodes[status]; ok {
|
||||
return platformapi.ErrLevelExceedLimit, newErr
|
||||
} else if _, ok := canRetryCodes[status]; ok {
|
||||
return platformapi.ErrLevelRecoverableErr, newErr
|
||||
} else {
|
||||
return platformapi.ErrLevelCodeIsNotOK, newErr
|
||||
}
|
||||
})
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func (a *API) BatchCoordinateConvert(coords []*Coordinate, fromCoordSys, toCoordSys int) (outCoords []*Coordinate, err error) {
|
||||
if fromCoordSys == toCoordSys {
|
||||
return coords, nil
|
||||
}
|
||||
var coordsStrList []string
|
||||
for _, v := range coords {
|
||||
coordsStrList = append(coordsStrList, fmt.Sprintf("%.6f,%.6f", v.Lng, v.Lat))
|
||||
}
|
||||
params := map[string]interface{}{
|
||||
"coords": strings.Join(coordsStrList, ";"),
|
||||
"from": fromCoordSys,
|
||||
"to": toCoordSys,
|
||||
}
|
||||
result, err := a.AccessAPI("geoconv/v1", params)
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(result, &outCoords, false)
|
||||
}
|
||||
return outCoords, err
|
||||
}
|
||||
41
platformapi/baidunavi/baidunavi_test.go
Normal file
41
platformapi/baidunavi/baidunavi_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package baidunavi
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
api *API
|
||||
sugarLogger *zap.SugaredLogger
|
||||
)
|
||||
|
||||
func init() {
|
||||
logger, _ := zap.NewDevelopment()
|
||||
sugarLogger = logger.Sugar()
|
||||
baseapi.Init(sugarLogger)
|
||||
|
||||
api = New("eL94zToVOdGDTkNQxV8dnEQ1ZRcB2UKb", "ZG0OOpOsOVURUwAkkmoHQFKRCbzn0zGb")
|
||||
}
|
||||
|
||||
func TestBatchCoordinateConvert(t *testing.T) {
|
||||
result, err := api.BatchCoordinateConvert([]*Coordinate{
|
||||
&Coordinate{
|
||||
Lng: 104.057367,
|
||||
Lat: 30.694686,
|
||||
},
|
||||
&Coordinate{
|
||||
Lng: 104.057367,
|
||||
Lat: 30.694686,
|
||||
},
|
||||
}, CoordSysGCJ02, CoordSysBaiDu)
|
||||
if err != nil {
|
||||
t.Fatalf("TestCoordinateConvert failed with error:%v", err)
|
||||
} else {
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
}
|
||||
@@ -145,7 +145,7 @@ func (a *API) ActivitySkuAddBatch(activityID int64, shopID string, baiduShopID i
|
||||
params[skusKey] = skuList2Str(activityType, skuList, isSkuIDCustom)
|
||||
result, err := a.AccessAPI("activity.sku.add.batch", params)
|
||||
if err == nil {
|
||||
return strings.Split(result.Data.(string), ","), nil
|
||||
return strings.Split(utils.Interface2String(result.Data), ","), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -180,7 +180,7 @@ func (a *API) ActivitySkuDeleteBatch(activityID int64, shopID string, baiduShopI
|
||||
params[skusKey] = strings.Join(skuIDs, ",")
|
||||
result, err := a.AccessAPI("activity.sku.delete.batch", params)
|
||||
if err == nil {
|
||||
return strings.Split(result.Data.(string), ","), nil
|
||||
return strings.Split(utils.Interface2String(result.Data), ","), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -236,7 +236,7 @@ func (a *API) ActivitySkuUpdateBatch(activityID int64, actSkuInfoList []*Activit
|
||||
"act_sku_info": actSkuInfoList,
|
||||
})
|
||||
if err == nil {
|
||||
return strings.Split(result.Data.(string), ";"), nil
|
||||
return strings.Split(utils.Interface2String(result.Data), ";"), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -113,16 +113,12 @@ func (a *API) unmarshalData(cmd string, data []byte, msg interface{}) (callbackR
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *API) CheckCallbackValidation(request *http.Request) (callbackResponse *CallbackResponse) {
|
||||
params := make(url.Values)
|
||||
for k, v := range request.PostForm {
|
||||
params[k] = v
|
||||
}
|
||||
func (a *API) CheckCallbackValidation(cmd string, params url.Values) (callbackResponse *CallbackResponse) {
|
||||
sign := a.signParams(params)
|
||||
if sign != request.FormValue(signKey) {
|
||||
msg := fmt.Sprintf("Signature is not ok, mine:%v, get:%v", sign, request.FormValue(signKey))
|
||||
if sign != params.Get(signKey) {
|
||||
msg := fmt.Sprintf("Signature is not ok, mine:%v, get:%v", sign, params.Get(signKey))
|
||||
baseapi.SugarLogger.Info(msg)
|
||||
return a.Err2CallbackResponse(GetCmd(request), errors.New(msg), nil)
|
||||
return a.Err2CallbackResponse(cmd, errors.New(msg), nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -130,15 +126,20 @@ func (a *API) CheckCallbackValidation(request *http.Request) (callbackResponse *
|
||||
func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackResponse *CallbackResponse) {
|
||||
err := request.ParseForm()
|
||||
if err == nil {
|
||||
if callbackResponse = a.CheckCallbackValidation(request); callbackResponse != nil {
|
||||
return nil, callbackResponse
|
||||
params := make(url.Values)
|
||||
for k := range request.PostForm {
|
||||
decodedValue, _ := url.QueryUnescape(request.PostFormValue(k))
|
||||
params.Set(k, decodedValue)
|
||||
}
|
||||
msg = new(CallbackMsg)
|
||||
if callbackResponse = a.unmarshalData(GetCmd(request), []byte(request.FormValue("body")), &msg.Body); callbackResponse != nil {
|
||||
msg.Cmd = GetCmd(request)
|
||||
if callbackResponse = a.CheckCallbackValidation(msg.Cmd, params); callbackResponse != nil {
|
||||
return nil, callbackResponse
|
||||
}
|
||||
msg.Cmd = GetCmd(request)
|
||||
msg.Timestamp = utils.Str2Int64(utils.Interface2String(request.FormValue("timestamp")))
|
||||
if callbackResponse = a.unmarshalData(msg.Cmd, []byte(params.Get("body")), &msg.Body); callbackResponse != nil {
|
||||
return nil, callbackResponse
|
||||
}
|
||||
msg.Timestamp = utils.Str2Int64(utils.Interface2String(params.Get("timestamp")))
|
||||
var tmpObj interface{}
|
||||
switch msg.Cmd {
|
||||
case CmdOrderPartRefund:
|
||||
@@ -158,6 +159,7 @@ func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackR
|
||||
return nil, a.Err2CallbackResponse("", err, nil)
|
||||
}
|
||||
|
||||
func GetCmd(request *http.Request) string {
|
||||
return request.FormValue("cmd")
|
||||
func GetCmd(request *http.Request) (cmd string) {
|
||||
cmd, _ = url.QueryUnescape(request.FormValue("cmd"))
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -15,18 +15,7 @@ type CityInfo struct {
|
||||
func (a *API) CommonShopCities(parentID int) (cityList []*CityInfo, err error) {
|
||||
result, err := a.AccessAPI("common.shopcities", utils.Params2Map("pid", parentID))
|
||||
if err == nil {
|
||||
cityMapList := utils.Slice2MapSlice(result.Data.([]interface{}))
|
||||
// baseapi.SugarLogger.Debug(utils.Format4Output(cityMapList, false))
|
||||
cityList = make([]*CityInfo, len(cityMapList))
|
||||
for k, v := range cityMapList {
|
||||
cityList[k] = &CityInfo{
|
||||
ID: int(utils.Str2Int64(utils.Interface2String(v["city_id"]))),
|
||||
Name: utils.Interface2String(v["city_name"]),
|
||||
ParentID: int(utils.Str2Int64(utils.Interface2String(v["parent_id"]))),
|
||||
IsOpen: int(utils.Str2Int64(utils.Interface2String(v["is_open"]))),
|
||||
}
|
||||
}
|
||||
return cityList, nil
|
||||
err = utils.Map2StructByJson(result.Data, &cityList, true)
|
||||
}
|
||||
return nil, err
|
||||
return cityList, err
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi"
|
||||
@@ -43,9 +42,6 @@ type API struct {
|
||||
config *platformapi.APIConfig
|
||||
speedLimiter *platformapi.Limiter
|
||||
supplierID int64
|
||||
|
||||
locker sync.RWMutex
|
||||
storeCookies map[string]string
|
||||
}
|
||||
|
||||
func New(source, secret string, config ...*platformapi.APIConfig) *API {
|
||||
@@ -60,7 +56,6 @@ func New(source, secret string, config ...*platformapi.APIConfig) *API {
|
||||
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||
config: &curConfig,
|
||||
speedLimiter: platformapi.New(apiLimitConfigs, nil), //defaultAPILimitConfig),
|
||||
storeCookies: make(map[string]string),
|
||||
|
||||
supplierID: -1,
|
||||
}
|
||||
@@ -155,12 +150,12 @@ func (a *API) AccessAPI(cmd string, body map[string]interface{}) (retVal *Respon
|
||||
}
|
||||
|
||||
func (a *API) GetSupplierID() (supplierID int64) {
|
||||
a.locker.RLock()
|
||||
a.RLock()
|
||||
supplierID = a.supplierID
|
||||
a.locker.RUnlock()
|
||||
a.RUnlock()
|
||||
if supplierID < 0 {
|
||||
a.locker.Lock()
|
||||
defer a.locker.Unlock()
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
a.supplierID = 0
|
||||
if shopList, err := a.ShopList(SysStatusAll); err == nil {
|
||||
|
||||
@@ -41,6 +41,7 @@ const (
|
||||
WaybillStatusSelfDelivery = "18" // 自行配送
|
||||
WaybillStatusDontDeliver = "19" // 不再配送
|
||||
WaybillStatusDeliveryRejected = "20" // 配送拒单
|
||||
WaybillStatusCourierArrived = "21" // 骑士到店
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -66,8 +67,6 @@ const (
|
||||
|
||||
OrderUserCancelTypeBeforeSale = 1 // 表示订单完成前用户全单取消申请流程
|
||||
OrderUserCancelTypeAfterSale = 2 // 表示订单完成后用户全单退款申请流程
|
||||
|
||||
SendImmediatelySelf = 6 // 饿百商家自送的配送状态
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -188,31 +187,31 @@ type OrderDetailInfo struct {
|
||||
Ext struct {
|
||||
TaoxiFlag int `json:"taoxi_flag"`
|
||||
} `json:"ext"`
|
||||
FinishedTime string `json:"finished_time"`
|
||||
InvoiceTitle string `json:"invoice_title"`
|
||||
IsColdBoxOrder int `json:"is_cold_box_order"`
|
||||
IsPrivate int `json:"is_private"`
|
||||
LatestSendTime int `json:"latest_send_time"`
|
||||
MealNum string `json:"meal_num"`
|
||||
NeedInvoice int `json:"need_invoice"`
|
||||
OrderFlag int `json:"order_flag"`
|
||||
OrderFrom string `json:"order_from"`
|
||||
OrderID string `json:"order_id"`
|
||||
OrderIndex string `json:"order_index"`
|
||||
PackageFee int `json:"package_fee"`
|
||||
PayStatus int `json:"pay_status"`
|
||||
PayType int `json:"pay_type"`
|
||||
PickupTime int `json:"pickup_time"`
|
||||
Remark string `json:"remark"`
|
||||
ResponsibleParty string `json:"responsible_party"`
|
||||
SendFee int `json:"send_fee"`
|
||||
SendImmediately int `json:"send_immediately"`
|
||||
SendTime int `json:"send_time"`
|
||||
ShopFee int `json:"shop_fee"`
|
||||
Status int `json:"status"`
|
||||
TaxerID string `json:"taxer_id"`
|
||||
TotalFee int `json:"total_fee"`
|
||||
UserFee int `json:"user_fee"`
|
||||
FinishedTime string `json:"finished_time"`
|
||||
InvoiceTitle string `json:"invoice_title"`
|
||||
IsColdBoxOrder int `json:"is_cold_box_order"`
|
||||
IsPrivate int `json:"is_private"`
|
||||
LatestSendTime int `json:"latest_send_time"`
|
||||
MealNum string `json:"meal_num"`
|
||||
NeedInvoice int `json:"need_invoice"`
|
||||
OrderFlag int `json:"order_flag"`
|
||||
OrderFrom string `json:"order_from"`
|
||||
OrderID string `json:"order_id"`
|
||||
OrderIndex string `json:"order_index"`
|
||||
PackageFee int `json:"package_fee"`
|
||||
PayStatus int `json:"pay_status"`
|
||||
PayType int `json:"pay_type"`
|
||||
PickupTime int `json:"pickup_time"`
|
||||
Remark string `json:"remark"`
|
||||
// ResponsibleParty string `json:"responsible_party"`
|
||||
SendFee int `json:"send_fee"`
|
||||
SendImmediately int `json:"send_immediately"`
|
||||
SendTime int `json:"send_time"`
|
||||
ShopFee int `json:"shop_fee"`
|
||||
Status int `json:"status"`
|
||||
TaxerID string `json:"taxer_id"`
|
||||
TotalFee int `json:"total_fee"`
|
||||
UserFee int `json:"user_fee"`
|
||||
} `json:"order"`
|
||||
Products [][]*OrderProductInfo `json:"products"`
|
||||
Shop *struct {
|
||||
@@ -223,8 +222,8 @@ type OrderDetailInfo struct {
|
||||
Source string `json:"source"`
|
||||
User *struct {
|
||||
Address string `json:"address"`
|
||||
City string `json:"city"`
|
||||
Coord *struct {
|
||||
// City string `json:"city"`
|
||||
Coord *struct {
|
||||
Latitude string `json:"latitude"`
|
||||
Longitude string `json:"longitude"`
|
||||
} `json:"coord"`
|
||||
@@ -232,13 +231,13 @@ type OrderDetailInfo struct {
|
||||
Latitude string `json:"latitude"`
|
||||
Longitude string `json:"longitude"`
|
||||
} `json:"coord_amap"`
|
||||
District string `json:"district"`
|
||||
// District string `json:"district"`
|
||||
Gender string `json:"gender"`
|
||||
Name string `json:"name"`
|
||||
Phone string `json:"phone"`
|
||||
PrivacyPhone string `json:"privacy_phone"`
|
||||
Province string `json:"province"`
|
||||
UserID string `json:"user_id"`
|
||||
// Province string `json:"province"`
|
||||
UserID string `json:"user_id"`
|
||||
} `json:"user"`
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,18 @@ const (
|
||||
DeliveryTypeElmXingHuoZBKA = 18 // 星火众包KA
|
||||
)
|
||||
|
||||
// https://open-be.ele.me/dev/api/doc/v3/#api-Order_Up-order_get
|
||||
const (
|
||||
DeliveryPartyFengNiao = 1 // 蜂鸟
|
||||
DeliveryPartyFengNiaoSelf = 2 // 蜂鸟自配送
|
||||
DeliveryPartyFengNiaoZB = 3 // 蜂鸟众包
|
||||
DeliveryPartyFengElmZB = 4 // 饿了么众包
|
||||
DeliveryPartyFengNiaoPS = 5 // 蜂鸟配送
|
||||
DeliveryPartyFengElmSelf = 6 // 饿了么自配送,商家自送?
|
||||
DeliveryPartyFullCity = 7 // 全城送
|
||||
DeliveryPartyKuaiDiPS = 8 // 快递配送
|
||||
)
|
||||
|
||||
type ShopInfo struct {
|
||||
ShopID string `json:"shop_id"`
|
||||
BaiduShopID int64 `json:"baidu_shop_id"`
|
||||
|
||||
@@ -237,7 +237,7 @@ func (a *API) ShopCategoryCreate(shopID string, parentID int64, name string, ran
|
||||
func (a *API) ShopCategoryGet(shopID string) (cats []*CategoryInfo, err error) {
|
||||
result, err := a.AccessAPI("sku.shop.category.get", utils.Params2Map(KeyShopID, shopID))
|
||||
if err == nil {
|
||||
if inMap, ok := result.Data.(map[string]interface{}); ok { // fuck it
|
||||
if inMap, ok := result.Data.(map[string]interface{}); ok {
|
||||
cats := interface2CatList(inMap["categorys"], 1)
|
||||
return cats, nil
|
||||
}
|
||||
@@ -252,11 +252,6 @@ func (a *API) ShopCategoryUpdate(shopID string, categoryID int64, name string, r
|
||||
"name": name,
|
||||
"rank": rank,
|
||||
})
|
||||
if errWithCode, ok := err.(*utils.ErrorWithCode); ok {
|
||||
if errWithCode.Level() == 0 && errWithCode.IntCode() == 1 { //忽略同名错误
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -367,8 +362,8 @@ func handleShopSkuBatchErr(err error) (opResult *BatchOpResult, outErr error) {
|
||||
var data interface{}
|
||||
if err2 := utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &data); err2 == nil {
|
||||
if err2 = utils.Map2StructByJson(data, &opResult, true); err2 == nil {
|
||||
// 将以\u表示的字符串标准化
|
||||
errExt.SetErrMsg(string(utils.MustMarshal(opResult)))
|
||||
// 将以\u表示的字符串标准化,并去掉成功的
|
||||
errExt.SetErrMsg(string(utils.MustMarshal(opResult.FailedList)))
|
||||
outErr = errExt
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ func TestShopCategoryCreate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestShopCategoryGet(t *testing.T) {
|
||||
result, err := api.ShopCategoryGet("102493")
|
||||
result, err := api.ShopCategoryGet("300034")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
@@ -69,7 +69,7 @@ func TestSkuUploadRTF(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSkuCreate(t *testing.T) {
|
||||
result, err := api.SkuCreate(testShopID, 17, map[string]interface{}{
|
||||
result, err := api.SkuCreate("", testShopID, 17, map[string]interface{}{
|
||||
"name": "测试商品",
|
||||
"status": SkuStatusOnline,
|
||||
"left_num": MaxLeftNum,
|
||||
|
||||
@@ -197,7 +197,7 @@ type PageListInnerShopInfo struct {
|
||||
ShopLabels string `json:"shop_labels"`
|
||||
ShopName string `json:"shop_name"`
|
||||
TakeoutCost float64 `json:"takeout_cost"`
|
||||
TakeoutPrice int `json:"takeout_price"`
|
||||
TakeoutPrice float64 `json:"takeout_price"`
|
||||
Type interface{} `json:"type"`
|
||||
WelfareInfo []struct {
|
||||
IconColor struct {
|
||||
@@ -263,39 +263,44 @@ type PageShopInfo struct {
|
||||
Tag []interface{} `json:"tag"`
|
||||
Text string `json:"text"`
|
||||
} `json:"delivery_mode"`
|
||||
Description string `json:"description"`
|
||||
DisplayRefundLabel int `json:"display_refund_label"`
|
||||
Distance int `json:"distance"`
|
||||
EleBusinessState int `json:"ele_business_state"`
|
||||
EleID string `json:"ele_id"`
|
||||
FirstOpenTime *BussinessTimeInfo `json:"first_open_time"`
|
||||
HitGod int `json:"hit_god"`
|
||||
ImagePath string `json:"image_path"`
|
||||
IsColdChain int `json:"is_cold_chain"`
|
||||
IsDoubleTwelve int `json:"is_double_twelve"`
|
||||
IsMedicineShop int `json:"is_medicine_shop"`
|
||||
IsOwnTheme int `json:"is_own_theme"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
MedicineQualification []interface{} `json:"medicine_qualification"`
|
||||
Name string `json:"name"`
|
||||
NewStyle bool `json:"new_style"`
|
||||
OTakoutCost int `json:"o_takout_cost"`
|
||||
OTakoutPrice int `json:"o_takout_price"`
|
||||
OrderLeadTime interface{} `json:"order_lead_time"`
|
||||
Phone string `json:"phone"`
|
||||
PromotionInfo string `json:"promotion_info"`
|
||||
Qualification string `json:"qualification"`
|
||||
RecentOrderNum int `json:"recent_order_num"`
|
||||
ShopID string `json:"shop_id"`
|
||||
ShopScore float64 `json:"shop_score"`
|
||||
ShopSourceFrom int `json:"shop_source_from"`
|
||||
SkuCount int `json:"sku_count"`
|
||||
TakeoutCost int `json:"takeout_cost"`
|
||||
TakeoutInvoice int `json:"takeout_invoice"`
|
||||
TakeoutInvoiceMinPrice string `json:"takeout_invoice_min_price"`
|
||||
TakeoutOpenTime string `json:"takeout_open_time"`
|
||||
TakeoutPrice int `json:"takeout_price"`
|
||||
Description string `json:"description"`
|
||||
DisplayRefundLabel int `json:"display_refund_label"`
|
||||
Distance int `json:"distance"`
|
||||
EleBusinessState int `json:"ele_business_state"`
|
||||
EleID string `json:"ele_id"`
|
||||
FirstOpenTime *BussinessTimeInfo `json:"first_open_time"`
|
||||
HitGod int `json:"hit_god"`
|
||||
ImagePath string `json:"image_path"`
|
||||
IsColdChain int `json:"is_cold_chain"`
|
||||
IsDoubleTwelve int `json:"is_double_twelve"`
|
||||
IsMedicineShop int `json:"is_medicine_shop"`
|
||||
IsOwnTheme int `json:"is_own_theme"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
MedicineQualification []*struct {
|
||||
AptitudeName string `json:"aptitude_name"`
|
||||
AptitudePhoto []string `json:"aptitude_photo"`
|
||||
AptitudeType string `json:"aptitude_type"`
|
||||
LicenseNumber string `json:"license_number"`
|
||||
} `json:"medicine_qualification"`
|
||||
Name string `json:"name"`
|
||||
NewStyle bool `json:"new_style"`
|
||||
OTakoutCost int `json:"o_takout_cost"`
|
||||
OTakoutPrice int `json:"o_takout_price"`
|
||||
OrderLeadTime interface{} `json:"order_lead_time"`
|
||||
Phone string `json:"phone"`
|
||||
PromotionInfo string `json:"promotion_info"`
|
||||
Qualification string `json:"qualification"`
|
||||
RecentOrderNum int `json:"recent_order_num"`
|
||||
ShopID string `json:"shop_id"`
|
||||
ShopScore float64 `json:"shop_score"`
|
||||
ShopSourceFrom int `json:"shop_source_from"`
|
||||
SkuCount int `json:"sku_count"`
|
||||
TakeoutCost float64 `json:"takeout_cost"`
|
||||
TakeoutInvoice float64 `json:"takeout_invoice"`
|
||||
TakeoutInvoiceMinPrice string `json:"takeout_invoice_min_price"`
|
||||
TakeoutOpenTime string `json:"takeout_open_time"`
|
||||
TakeoutPrice float64 `json:"takeout_price"`
|
||||
}
|
||||
|
||||
func (a *API) AccessStorePage2(subURL string, params map[string]interface{}, isPost bool, cookies map[string]string) (retVal map[string]interface{}, err error) {
|
||||
@@ -515,22 +520,45 @@ func (a *API) PageGetCustomCatList(baiduShopID int64) (catList []map[string]inte
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (a *API) GetStoreList(lng string, lat string) (retVal map[string]interface{}, err error) {
|
||||
func (a *API) GetStoreList(lng string, lat string, pageNo, pageSize int) (shopListInfo *PageListInfo, err error) {
|
||||
if pageNo <= 0 {
|
||||
pageNo = 1
|
||||
}
|
||||
if pageSize > 20 || pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
params := map[string]interface{}{
|
||||
"channel": "kitchen",
|
||||
"pn": 1,
|
||||
"rn": 999,
|
||||
"rn": pageSize,
|
||||
"pn": pageNo,
|
||||
"lng": lng,
|
||||
"lat": lat,
|
||||
}
|
||||
retVal, err = a.AccessStorePageNoCookie("/newretail/main/shoplist", params)
|
||||
return retVal, err
|
||||
result, err := a.AccessStorePageNoCookie("newretail/main/shoplist", params)
|
||||
if err == nil && result != nil {
|
||||
err = utils.Map2StructByJson(result, &shopListInfo, true)
|
||||
}
|
||||
return shopListInfo, err
|
||||
}
|
||||
|
||||
func (a *API) GetStoreList2(lng float64, lat float64) (shopListInfo *PageListInfo, err error) {
|
||||
retVal, err := a.GetStoreList(fmt.Sprintf("%.6f", lng), fmt.Sprintf("%.6f", lat))
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(retVal, &shopListInfo, true)
|
||||
pageSize := 20
|
||||
pageNo := 1
|
||||
for {
|
||||
retVal, err2 := a.GetStoreList(fmt.Sprintf("%.6f", lng), fmt.Sprintf("%.6f", lat), pageNo, pageSize)
|
||||
if err = err2; err == nil {
|
||||
if shopListInfo == nil {
|
||||
shopListInfo = retVal
|
||||
} else {
|
||||
shopListInfo.ShopList = append(shopListInfo.ShopList, retVal.ShopList...)
|
||||
}
|
||||
if len(retVal.ShopList) < pageSize {
|
||||
break
|
||||
}
|
||||
pageNo++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return shopListInfo, err
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func TestGetShopHealthByDetail(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetStoreList(t *testing.T) {
|
||||
result, err := api.GetStoreList("104.057218", "30.6949")
|
||||
result, err := api.GetStoreList("104.057218", "30.6949", 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -115,7 +115,7 @@ func TestGetStoreList(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetStoreList2(t *testing.T) {
|
||||
result, err := api.GetStoreList2(120.074911, 29.306863)
|
||||
result, err := api.GetStoreList2(104.010554, 30.637072)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package jdapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
|
||||
@@ -66,9 +66,6 @@ type API struct {
|
||||
appSecret string
|
||||
client *http.Client
|
||||
config *platformapi.APIConfig
|
||||
|
||||
locker sync.RWMutex
|
||||
storeCookie string
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -105,7 +102,8 @@ var (
|
||||
KeyOutStationNo,
|
||||
KeyStationNo,
|
||||
"StoreNo",
|
||||
"outSkuId",
|
||||
KeyOutSkuId,
|
||||
KeySkuId,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -120,13 +118,14 @@ func (a *API) signParams(jdParams map[string]interface{}) string {
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
allStr := a.appSecret
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString(a.appSecret)
|
||||
for _, k := range keys {
|
||||
allStr += k + fmt.Sprint(jdParams[k])
|
||||
buf.WriteString(k)
|
||||
buf.WriteString(fmt.Sprint(jdParams[k]))
|
||||
}
|
||||
allStr = allStr + a.appSecret
|
||||
|
||||
return fmt.Sprintf("%X", md5.Sum([]byte(allStr)))
|
||||
buf.WriteString(a.appSecret)
|
||||
return fmt.Sprintf("%X", md5.Sum(buf.Bytes()))
|
||||
}
|
||||
|
||||
func New(token, appKey, appSecret string, config ...*platformapi.APIConfig) *API {
|
||||
@@ -143,6 +142,13 @@ func New(token, appKey, appSecret string, config ...*platformapi.APIConfig) *API
|
||||
}
|
||||
}
|
||||
|
||||
func NewPageOnly(cookie string, config ...*platformapi.APIConfig) *API {
|
||||
api := New("", "", "", config...)
|
||||
api.SetCookie(accessStorePageCookieName, cookie)
|
||||
api.SetCookie(accessStorePageCookieName2, cookie)
|
||||
return api
|
||||
}
|
||||
|
||||
func (a *API) AccessAPI2(apiStr string, jdParams map[string]interface{}, traceInfo string) (retVal map[string]interface{}, err error) {
|
||||
params := make(map[string]interface{})
|
||||
params["v"] = "1.0"
|
||||
@@ -267,59 +273,60 @@ func (a *API) AccessAPINoPage2(apiStr string, jdParams map[string]interface{}, k
|
||||
func (a *API) AccessAPINoPage(apiStr string, jdParams map[string]interface{}, keyToRemove, keyToKeep []string, resultParser func(data map[string]interface{}) (interface{}, error)) (interface{}, error) {
|
||||
return a.AccessAPINoPage2(apiStr, jdParams, keyToRemove, keyToKeep, resultParser, "")
|
||||
}
|
||||
func genNormalHavePageResultParser(dataKey string) (handler PageResultParser) {
|
||||
return func(data map[string]interface{}, totalCount int) ([]interface{}, int, error) {
|
||||
var result map[string]interface{}
|
||||
var retVal []interface{}
|
||||
|
||||
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
|
||||
tempResult := data[dataKey]
|
||||
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 {
|
||||
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 inner2Result == nil {
|
||||
retVal = nil
|
||||
} else if inner2ResultStr, ok := inner2Result.(string); ok {
|
||||
err := utils.UnmarshalUseNumber([]byte(inner2ResultStr), &retVal)
|
||||
if err != nil {
|
||||
return nil, 0, platformapi.ErrResponseDataFormatWrong
|
||||
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
|
||||
}
|
||||
} else {
|
||||
retVal = inner2Result.([]interface{})
|
||||
}
|
||||
return retVal, totalCount, nil
|
||||
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 inner2Result == nil {
|
||||
retVal = nil
|
||||
} else 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
|
||||
}
|
||||
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{}, int, error) {
|
||||
if pageResultParser == nil {
|
||||
pageResultParser = normalHavePageResultParser
|
||||
pageResultParser = genNormalHavePageResultParser("result")
|
||||
}
|
||||
|
||||
localJdParams := make(map[string]interface{})
|
||||
|
||||
@@ -23,11 +23,11 @@ func init() {
|
||||
// sandbox
|
||||
api = New("df97f334-f7d8-4b36-9664-5784d8ae0baf", "06692746f7224695ad4788ce340bc854", "d6b42a35a7414a5490d811654d745c84")
|
||||
// prod
|
||||
// api = New("ccb10daf-e6f5-4a58-ada5-b97f9073a137", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4")
|
||||
// api = New("77e703b7-7997-441b-a12a-2e522efb117a", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4")
|
||||
// 天天果园
|
||||
// api = New("84541069-fbe2-424b-b625-9b2ba1d4c9e6", "5d5577a2506f41b8b4ec520ba83490f5", "0b01b9eeb15b41dab1c3d05d95c17a26")
|
||||
|
||||
const cookieValue = "YYJV3NHVBPHLD36FWP6F3EM5PTXJ2XZQS7U4HWRIDPP4IWGUKUIB4XG5N26CZRDLDF7PKOXBPD6BNTUAJLETLZOIWMCVFI3K6MYZIY4QBIXIMXYDJNUKFGJVQTN5356SAD6WPCIHWNQAG7DDMF7L7S3SHDYZP7PPVMRGO4VWG2JRBMKFTOGIWZ5L2XHXC3SXQ4OLX7EL4RKUPZQT6GOH63KE3EVK37L5LG7TGSDGXFQP4377YK72UB5YZG6IJH6PY25YLLCJYPMDSHKPGYBUFJ4MMMKGN6MWB37CP7XVDBBZJ3U462ENTEXH744AWCQCIG2AAE2PKYVHC"
|
||||
const cookieValue = "YYJV3NHVBPHLD36FWP6F3EM5PTXJ2XZQS7U4HWRIDPP4IWGUKUIB4XG5N26CZRDLDF7PKOXBPD6BNTUAJLETLZOIWMCVFI3K6MYZIY4QBIXIMXYDJNUKFGJVQTN5356SAD6WPCIHWNQAG7DDMF7L7S3SHCT3RM3CQG7IJIPUQ3THS5UIUYWMKINM7ETUOQB7OBPOPZVCT3ZJY55243TDVXLO25PP4UYSPTTPMNQ7HPMWOJKJ3BJWGVHD243MXH7NZWW264TKN5UOCJBSSSOKD2QQII"
|
||||
api.SetCookie(accessStorePageCookieName, cookieValue)
|
||||
api.SetCookie(accessStorePageCookieName2, cookieValue)
|
||||
}
|
||||
|
||||
@@ -37,11 +37,10 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
FreightDiscountTypeByShop = 8 // 8:商家满免运费
|
||||
FreightDiscountTypeByVip = 7 // 7:VIP免运费
|
||||
FreightDiscountTypeByActivity = 12 // 12:首单地推满免运费
|
||||
FreightDiscountTypeByCoupons = 15 // 15:运费券
|
||||
SelfDeliveryCarrierNo = "2938" // 京东配送方式=商家自送
|
||||
FreightDiscountTypeByShop = 8 // 8:商家满免运费
|
||||
FreightDiscountTypeByVip = 7 // 7:VIP免运费
|
||||
FreightDiscountTypeByActivity = 12 // 12:首单地推满免运费
|
||||
FreightDiscountTypeByCoupons = 15 // 15:运费券
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -59,16 +58,17 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
AfsReasonTypeGoodsQuality = 201 // 商品质量问题/做工粗糙/有瑕疵
|
||||
AfsReasonTypeWrongGoods = 202 // 发错货
|
||||
AfsReasonTypeMissingGoods = 203 // 部分商品未收到
|
||||
AfsReasonTypeNoGoods = 501 // 全部商品未收到
|
||||
AfsReasonTypeDamagedGoods = 208 // 外表损伤(压坏,磕坏等)
|
||||
AfsReasonTypeGoodsQuantity = 207 // 缺斤少两
|
||||
AfsReasonTypeAgreedByMerchant = 209 // 与商家协商一致
|
||||
AfsReasonTypeGoodsQuality = 201 // 商品质量问题
|
||||
AfsReasonTypeWrongGoods = 202 // 送错货
|
||||
AfsReasonTypeMissingGoods = 203 // 缺件少件
|
||||
AfsReasonTypeNoGoods = 501 // 全部商品未收到
|
||||
AfsReasonTypeDamagedGoods = 208 // 包装脏污有破损
|
||||
AfsReasonTypeGoodsQuantity = 207 // 缺斤少两
|
||||
// AfsReasonTypeAgreedByMerchant = 209 // 与商家协商一致,2019/09/01取消
|
||||
AfsReasonTypeGoodsAbsent = 210 // 商家通知我缺货
|
||||
AfsReasonTypeGoodsSizeNoSame = 302 // 大小尺寸与商品描述不符
|
||||
AfsReasonTypeGoodsColorNoSame = 303 // 颜色/款式/图案与描述不符
|
||||
AfsReasonWrongPurchase = 402 // 误购
|
||||
AfsReasonTypeGoodsColorNoSame = 303 // 实物与原图不符
|
||||
AfsReasonWrongPurchase = 402 // 不想要了
|
||||
AfsReasonNotReceivedIntime = 502 // 未在时效内送达
|
||||
)
|
||||
|
||||
@@ -310,6 +310,48 @@ type OrderInfo struct {
|
||||
Yn bool `json:"yn"`
|
||||
}
|
||||
|
||||
type OrderQueryParam struct {
|
||||
PageNo int64 `json:"pageNo,omitempty"` // 当前页数,默认:1
|
||||
PageSize int `json:"pageSize,omitempty"` // 每页条数,默认:20,最大值100
|
||||
OrderID int64 `json:"orderId,omitempty"`
|
||||
|
||||
OrderPurchaseTimeBegin string `json:"orderPurchaseTime_begin,omitempty"` // 购买成交时间-支付(开始)
|
||||
OrderPurchaseTimeEnd string `json:"orderPurchaseTime_end,omitempty"` // 购买成交时间-支付(结束)
|
||||
OrderStatus int `json:"orderStatus,omitempty"`
|
||||
|
||||
DeliveryStationNo string `json:"deliveryStationNo,omitempty"` // 到家门店编码
|
||||
DeliveryStationNoIsv string `json:"deliveryStationNoIsv,omitempty"` // 商家门店编码
|
||||
}
|
||||
|
||||
type SonTag struct {
|
||||
MqProcessTime string `json:"mqProcessTime"`
|
||||
OperTime string `json:"operTime"`
|
||||
TagCode int `json:"tagCode"`
|
||||
CodeName string `json:"codeName"`
|
||||
OperPin string `json:"operPin"`
|
||||
OperName int `json:"operName"`
|
||||
MsgContent string `json:"msgContent"`
|
||||
}
|
||||
|
||||
type OrderTrack struct {
|
||||
SonTagList []*SonTag `json:"sonTagList"`
|
||||
IsThirdCarry int `json:"isThirdCarry"`
|
||||
OperFrom string `json:"operFrom"`
|
||||
MqProcessTime string `json:"mqProcessTime"`
|
||||
TagIcon string `json:"tagIcon"`
|
||||
OperTime string `json:"operTime"`
|
||||
ThirdCarry int `json:"thirdCarry"`
|
||||
TagTitle string `json:"tagTitle"`
|
||||
CodeName string `json:"codeName"`
|
||||
TagCode int `json:"tagCode"`
|
||||
OperPin string `json:"operPin"`
|
||||
OperName string `json:"operName"`
|
||||
Care bool `json:"care"`
|
||||
MsgContent string `json:"msgContent"`
|
||||
MsgContentApp string `json:"msgContentApp"`
|
||||
DoNotCareReason string `json:"doNotCareReason"`
|
||||
}
|
||||
|
||||
var (
|
||||
ErrCanNotFindOrder = errors.New("can not find order")
|
||||
)
|
||||
@@ -336,14 +378,6 @@ func (a *API) OrderQuery(jdParams map[string]interface{}) (retVal []interface{},
|
||||
return retVal, totalCount, err
|
||||
}
|
||||
|
||||
func (a *API) OrderQuery2(jdParams map[string]interface{}) (retVal []*OrderInfo, totalCount int, err error) {
|
||||
orderList, totalCount, err := a.OrderQuery(jdParams)
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(orderList, &retVal, true)
|
||||
}
|
||||
return retVal, totalCount, err
|
||||
}
|
||||
|
||||
// orderFreightMoney 基础运费
|
||||
// tips 商家承担小费
|
||||
// merchantPaymentDistanceFreightMoney 取件服务费(开票)(正向单展示远距离运费;售后单则展示达达售后运费)
|
||||
@@ -361,6 +395,28 @@ func (a *API) QuerySingleOrder(orderId string) (map[string]interface{}, error) {
|
||||
return result[0].(map[string]interface{}), nil
|
||||
}
|
||||
|
||||
func (a *API) OrderQuery2(queryParam *OrderQueryParam) (retVal []*OrderInfo, totalCount int, err error) {
|
||||
orderList, totalCount, err := a.OrderQuery(utils.Struct2MapByJson(queryParam))
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(orderList, &retVal, true)
|
||||
}
|
||||
return retVal, totalCount, err
|
||||
}
|
||||
|
||||
func (a *API) QuerySingleOrder2(orderID string) (orderInfo *OrderInfo, err error) {
|
||||
orderList, _, err := a.OrderQuery2(&OrderQueryParam{
|
||||
OrderID: utils.Str2Int64(orderID),
|
||||
})
|
||||
if err == nil {
|
||||
if len(orderList) > 0 {
|
||||
orderInfo = orderList[0]
|
||||
} else {
|
||||
err = ErrCanNotFindOrder
|
||||
}
|
||||
}
|
||||
return orderInfo, err
|
||||
}
|
||||
|
||||
// 商家确认接单接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=169&apiid=c1a15129d1374e9da7fa35487f878604
|
||||
func (a *API) OrderAcceptOperate(orderId string, isAgreed bool, userName string) error {
|
||||
@@ -588,6 +644,7 @@ func (a *API) AfsSubmit(OrderID, pin, questionTypeCode, questionDesc, questionPi
|
||||
"orderId": OrderID,
|
||||
"pin": utils.GetAPIOperator(pin),
|
||||
"questionTypeCode": questionTypeCode,
|
||||
"skuList": skuList,
|
||||
}
|
||||
if questionDesc != "" {
|
||||
jdParams["questionDesc"] = questionDesc
|
||||
@@ -624,13 +681,53 @@ func ProcessQuestionPic(questionPic string) (outQuestionPic string) {
|
||||
}
|
||||
|
||||
// 订单商家加小费接口
|
||||
// tips必须是100的倍数,另外必须要等到家下发运单后才能调用,否则会报“订单号srcOrderNo的订单不存在”错
|
||||
// 这个tips是累计增的,比如第一次调用tips为100,再一次调用tips为200,则总共的tips就是300
|
||||
// https://openo2o.jddj.com/staticnew/widgets/resources.html?groupid=169&apiid=ed9e3ca7325c4d4d8ceaf959ed0e7a62
|
||||
func (a *API) OrderAddTips(OrderID string, tips int, pin string) (err error) {
|
||||
func (a *API) OrderAddTips(orderID string, tips int, operator string) (err error) {
|
||||
jdParams := map[string]interface{}{
|
||||
"orderId": OrderID,
|
||||
"tips": tips,
|
||||
"pin": utils.GetAPIOperator(pin),
|
||||
"orderId": orderID,
|
||||
"tips": tips,
|
||||
"operator": utils.GetAPIOperator(operator),
|
||||
}
|
||||
_, err = a.AccessAPINoPage("order/addTips", jdParams, nil, nil, nullResultParser)
|
||||
return err
|
||||
}
|
||||
|
||||
// 根据订单号查询订单跟踪接口
|
||||
// https://openo2o.jddj.com/staticnew/widgets/resources.html?groupid=169&apiid=d9d4fd73fba14fd8851a4c054d2ee42e
|
||||
func (a *API) GetByOrderNoForOaos(orderNo string) (orderTrackList []*OrderTrack, err error) {
|
||||
jdParams := map[string]interface{}{
|
||||
"orderNo": orderNo,
|
||||
}
|
||||
result, err := a.AccessAPINoPage("orderTrace/getByOrderNoForOaos", jdParams, nil, nil, genNoPageResultParser("code", "msg", "orderTrackList", "0"))
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(result, &orderTrackList, false)
|
||||
}
|
||||
return orderTrackList, err
|
||||
}
|
||||
|
||||
// 新版根据订单号查询订单跟踪接口
|
||||
// https://openo2o.jddj.com/staticnew/widgets/resources.html?groupid=169&apiid=6450cd91dd5b4dc0bb6a6cd17af6d0a4
|
||||
func (a *API) GetByOrderNoForOaosNew(orderID string) (orderTrackList []*OrderTrack, err error) {
|
||||
jdParams := map[string]interface{}{
|
||||
"orderId": orderID,
|
||||
}
|
||||
result, err := a.AccessAPINoPage("orderTrace/getByOrderNoForOaosNew", jdParams, nil, nil, genNoPageResultParser("code", "detail", "result", "0"))
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(result.(map[string]interface{})["orderTrackList"], &orderTrackList, false)
|
||||
}
|
||||
return orderTrackList, err
|
||||
}
|
||||
|
||||
// 订单自提码核验接口
|
||||
// https://openo2o.jddj.com/staticnew/widgets/resources.html?groupid=169&apiid=428fa2cb66784b64a85db36ec2972ff9
|
||||
func (a *API) CheckSelfPickCode(selfPickCode, orderID, operPin string) (err error) {
|
||||
jdParams := map[string]interface{}{
|
||||
"selfPickCode": selfPickCode,
|
||||
"orderId": orderID,
|
||||
"operPin": operPin,
|
||||
}
|
||||
_, err = a.AccessAPINoPage("ocs/checkSelfPickCode", jdParams, nil, nil, nullResultParser)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ import (
|
||||
)
|
||||
|
||||
func TestQuerySingleOrder(t *testing.T) {
|
||||
retVal, err := api.QuerySingleOrder("815536199000222")
|
||||
retVal, err := api.QuerySingleOrder("921160248000222")
|
||||
t.Log(utils.Format4Output(retVal, false))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -218,3 +219,43 @@ func TestOrderShoudSettlementService2(t *testing.T) {
|
||||
}
|
||||
sugarLogger.Debug(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
func TestOrderAddTips(t *testing.T) {
|
||||
err := api.OrderAddTips("918092290000042", 50, "xjh")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderQuery2(t *testing.T) {
|
||||
orderList, _, err := api.OrderQuery2(&OrderQueryParam{
|
||||
OrderID: 918092290000042,
|
||||
})
|
||||
t.Log(utils.Format4Output(orderList, false))
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetByOrderNoForOaos(t *testing.T) {
|
||||
orderList, err := api.GetByOrderNoForOaos("921235438000341")
|
||||
t.Log(utils.Format4Output(orderList, false))
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetByOrderNoForOaosNew(t *testing.T) {
|
||||
orderList, err := api.GetByOrderNoForOaosNew("921235438000341")
|
||||
t.Log(utils.Format4Output(orderList, false))
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckSelfPickCode(t *testing.T) {
|
||||
err := api.CheckSelfPickCode("020606", "921235438000341", "test")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,3 +106,18 @@ func (a *API) QueryPromotionInfo(promotionInfoId int64) (promotionInfo *Promotio
|
||||
}
|
||||
return promotionInfo, err
|
||||
}
|
||||
|
||||
// 根据到家商品ID查询单品级优惠活动列表接口
|
||||
// https://openo2o.jddj.com/staticnew/widgets/resources.html?groupid=196&apiid=d73baba02c484109a3c3c1b1236ca13d
|
||||
func (a *API) QueryPromotionSku(promotionType int, skuID int64, promotionState int /*, pageNo int64, pageSize int*/) (skuResultList []*PromotionLspQuerySkuResult, err error) {
|
||||
jdParams := map[string]interface{}{
|
||||
"promotionType": promotionType,
|
||||
"skuId": skuID,
|
||||
"promotionState": promotionState,
|
||||
}
|
||||
result, _, err := a.AccessAPIHavePage("singlePromote/queryPromotionSku", jdParams, nil, nil, genNormalHavePageResultParser("data"))
|
||||
if err != nil {
|
||||
err = utils.Map2StructByJson(result, &skuResultList, false)
|
||||
}
|
||||
return skuResultList, err
|
||||
}
|
||||
|
||||
@@ -21,3 +21,24 @@ func TestQueryPromotionInfo(t *testing.T) {
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
func TestQueryPromotionSku(t *testing.T) {
|
||||
skuIDs := []int64{
|
||||
2023335105,
|
||||
// 2023335104,
|
||||
// 2023335088,
|
||||
// 2023335057,
|
||||
// 2023335098,
|
||||
// 2023335020,
|
||||
}
|
||||
for _, skuID := range skuIDs {
|
||||
list, err := api.QueryPromotionSku(PromotionTypeDirectDown, skuID, PromotionStateConfirmed)
|
||||
t.Log(utils.Format4Output(list, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// for _, v := range list {
|
||||
// CancelPromotionSkuSingle()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,3 +76,70 @@ func TestCreatePromotionSkuLimitTime(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelPromotion(t *testing.T) {
|
||||
promotionIDs := []int64{
|
||||
24636389,
|
||||
24753178,
|
||||
24754087,
|
||||
24970355,
|
||||
24970383,
|
||||
24970389,
|
||||
25439508,
|
||||
25444342,
|
||||
25869363,
|
||||
25871946,
|
||||
26291079,
|
||||
27036663,
|
||||
27407558,
|
||||
27407649,
|
||||
27424152,
|
||||
27424181,
|
||||
27424247,
|
||||
27424568,
|
||||
27508490,
|
||||
27555133,
|
||||
27674289,
|
||||
30969372,
|
||||
41809699,
|
||||
41810076,
|
||||
41810296,
|
||||
41811111,
|
||||
44179379,
|
||||
54080816,
|
||||
54080829,
|
||||
54080842,
|
||||
55346987,
|
||||
55347123,
|
||||
55347340,
|
||||
55348499,
|
||||
55348706,
|
||||
55348999,
|
||||
55349177,
|
||||
56723852,
|
||||
56724283,
|
||||
56725840,
|
||||
56725955,
|
||||
56726053,
|
||||
60713479,
|
||||
60714768,
|
||||
60719242,
|
||||
68818338,
|
||||
}
|
||||
|
||||
for _, v := range promotionIDs {
|
||||
promotionInfo, err := api.QueryPromotionInfo(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// t.Log(promotionInfo.PromotionType)
|
||||
if promotionInfo.PromotionType == PromotionTypeLimitedTime {
|
||||
err = api.CancelPromotionLimitTime(v, "", utils.GetUUID())
|
||||
} else {
|
||||
err = api.CancelPromotionSingle(v, "", utils.GetUUID())
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package jdapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -65,12 +63,14 @@ const (
|
||||
|
||||
const (
|
||||
MaxBatchSize4BatchUpdateOutSkuId = 50
|
||||
MaxPageSize4QuerySku = 50
|
||||
MaxSkuIDsCount4QueryListBySkuIds = 25
|
||||
)
|
||||
|
||||
const (
|
||||
SkuFixedStatusOnline = 1
|
||||
SkuFixedStatusOffline = 2
|
||||
SkuFixedStatusDeleted = 4
|
||||
SkuFixedStatusOnline = 1 // 上架
|
||||
SkuFixedStatusOffline = 2 // 下架
|
||||
SkuFixedStatusDeleted = 4 // 删除
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -79,12 +79,21 @@ const (
|
||||
CreateSpuResultFailed = 3
|
||||
)
|
||||
|
||||
const (
|
||||
IsFilterDelTrue = "0" // 0代表不查已删除商品
|
||||
)
|
||||
|
||||
const (
|
||||
MaxSkuNameCharCount = 45 // skuname最长字符数
|
||||
SaleAttrIDBase = 1001
|
||||
SaleAttrValueIDBase = 10
|
||||
)
|
||||
|
||||
const (
|
||||
ImgTypeMain = 1 // 商品图片
|
||||
ImgTypeDetail = 2 // 详情图片
|
||||
)
|
||||
|
||||
type SkuIDPair struct {
|
||||
SkuId int64 `json:"skuId"`
|
||||
OutSkuId string `json:"outSkuId"`
|
||||
@@ -119,11 +128,11 @@ type CategoryInfo struct {
|
||||
}
|
||||
|
||||
type CreateByUpcParam struct {
|
||||
Upc string
|
||||
OutSkuId string
|
||||
Price int // 单位为分
|
||||
ShopCategoryId int64
|
||||
IsSale bool
|
||||
UniqueUpc string `json:"uniqueCode"` // 商品UPC码
|
||||
OutSku string `json:"outSku"` // 商家商品编码,商家系统中唯一编码,限1-35字符,与到家商品编码一对一对应
|
||||
JdPrice string `json:"jdPrice"` // 商家商品价格(单位:元),用于初始商品门店价格,所有的商品门店价格都会初始化成该值。后续修改商品门店价格需要通过价格类接口修改。
|
||||
ShopCategoryID int64 `json:"shopCategoryId"` // 商家店内分类编码,店内分类编码通过查询商家店内分类信息接口获取
|
||||
IsSale bool `json:"isSale"` // 门店商品可售状态,true为可售,false为不可售,默认为可售。
|
||||
}
|
||||
|
||||
type CreateByUpcPair struct {
|
||||
@@ -131,13 +140,58 @@ type CreateByUpcPair struct {
|
||||
SkuId int64
|
||||
}
|
||||
|
||||
type QuerySkuParam struct {
|
||||
SkuName string `json:"skuName,omitempty"`
|
||||
UpcCode string `json:"upcCode,omitempty"`
|
||||
SkuID int64 `json:"skuId,omitempty"`
|
||||
IsFilterDel string `json:"isFilterDel,omitempty"` // 是否查询出已删除的上传商品(0代表不查已删除商品,不填则查出全部商品)
|
||||
PageNo int `json:"pageNo,omitempty"`
|
||||
PageSize int `json:"pageSize,omitempty"`
|
||||
}
|
||||
|
||||
type SkuMain struct {
|
||||
SuperID int64 `json:"superId"`
|
||||
SkuID int64 `json:"skuId"`
|
||||
OutSkuID string `json:"outSkuId"`
|
||||
CategoryID int64 `json:"categoryId"`
|
||||
BrandID int64 `json:"brandId"`
|
||||
ShopCategories []int64 `json:"shopCategories"`
|
||||
SkuName string `json:"skuName"`
|
||||
Slogan string `json:"slogan"`
|
||||
FixedStatus int `json:"fixedStatus"` // 商家商品上下架状态(1:上架;2:下架;4:删除;)
|
||||
FixedUpTime string `json:"fixedUpTime"`
|
||||
OrgCode int `json:"orgCode"`
|
||||
SellCities []int64 `json:"sellCities"`
|
||||
SkuPrice int `json:"skuPrice"`
|
||||
Weight float64 `json:"weight"`
|
||||
}
|
||||
|
||||
type QueryListBySkuIdsParam struct {
|
||||
SkuIDs []int64 `json:"skuIds"`
|
||||
ImgType int `json:"imgType,omitempty"`
|
||||
HandleStatus []int `json:"handleStatus,omitempty"`
|
||||
}
|
||||
|
||||
type ImgHandleQueryResult struct {
|
||||
ID string `json:"id"`
|
||||
SkuID int64 `json:"skuId"`
|
||||
IsMain int `json:"isMain"`
|
||||
ImgType int `json:"imgType"`
|
||||
SourceImgURL string `json:"sourceImgUrl"`
|
||||
SkuImgSort int `json:"skuImgSort"`
|
||||
HandleStatus int `json:"handleStatus"`
|
||||
HandleStatusStr string `json:"handleStatusStr"`
|
||||
HandleRemark string `json:"handleRemark"`
|
||||
HandleErrLog string `json:"handleErrLog"`
|
||||
}
|
||||
|
||||
var (
|
||||
skuExistReg = regexp.MustCompile(`商家skuId已存在:(\d+)`)
|
||||
)
|
||||
|
||||
// 分页查询商品品牌信息接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=1ca07a3e767649a7a44fc6ea7e9ed8dd
|
||||
func (a *API) QueryPageBrandInfo(pageNo, pageSize, brandId int, brandName string) (brandList []*BrandInfo, totalCount int, err error) {
|
||||
func (a *API) QueryPageBrandInfo(pageNo, pageSize int, brandId int64, brandName string) (brandList []*BrandInfo, totalCount int, err error) {
|
||||
if pageNo <= 0 {
|
||||
pageNo = 1
|
||||
}
|
||||
@@ -320,44 +374,28 @@ func (a *API) BatchUpdateOutSkuId(skuInfoList []*SkuIDPair) (retVal interface{},
|
||||
// 查询商家已上传商品信息列表接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=e433b95f74524dab91718432c0358977
|
||||
// pageNo 从1开始
|
||||
func (a *API) QuerySkuInfos(skuName string, skuId int64, pageNo, pageSize int, isFilterDel bool) (retVal []map[string]interface{}, totalCount int, err error) {
|
||||
if pageNo <= 0 {
|
||||
pageNo = 1
|
||||
func (a *API) QuerySkuInfos(queryParam *QuerySkuParam) (skuList []*SkuMain, totalCount int, err error) {
|
||||
if queryParam.PageNo <= 0 {
|
||||
queryParam.PageNo = 1
|
||||
}
|
||||
if pageSize == 0 {
|
||||
pageSize = 50
|
||||
if queryParam.PageSize == 0 {
|
||||
queryParam.PageSize = MaxPageSize4QuerySku
|
||||
}
|
||||
params := map[string]interface{}{
|
||||
KeyPageNo: pageNo, // pageNo好像必须要有值,否则一直不返回
|
||||
KeyPageSize: pageSize,
|
||||
}
|
||||
if skuName != "" {
|
||||
params[KeySkuName] = skuName
|
||||
}
|
||||
if skuId != 0 {
|
||||
params[KeySkuId] = skuId
|
||||
}
|
||||
if isFilterDel {
|
||||
params[KeyIsFilterDel] = "1"
|
||||
} else {
|
||||
params[KeyIsFilterDel] = "0"
|
||||
}
|
||||
result, totalCount, err := a.AccessAPIHavePage("pms/querySkuInfos", params, nil, nil, nil)
|
||||
result, totalCount, err := a.AccessAPIHavePage("pms/querySkuInfos", utils.Struct2MapByJson(queryParam), nil, nil, nil)
|
||||
if err == nil {
|
||||
return utils.Slice2MapSlice(result), totalCount, nil
|
||||
err = utils.Map2StructByJson(result, &skuList, false)
|
||||
}
|
||||
return nil, 0, err
|
||||
return skuList, totalCount, err
|
||||
}
|
||||
|
||||
// 查询商品图片处理结果接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=17506653e03542f9a49023711780c30d
|
||||
func (a *API) QueryListBySkuIds(skuIds []int64, addParams map[string]interface{}) (retVal []map[string]interface{}, err error) {
|
||||
result, err := a.AccessAPINoPage("order/queryListBySkuIds", utils.MergeMaps(addParams, utils.Params2Map("skuIds", skuIds)), nil, nil, nil)
|
||||
func (a *API) QueryListBySkuIds(queryParam *QueryListBySkuIdsParam) (imgList []*ImgHandleQueryResult, err error) {
|
||||
result, err := a.AccessAPINoPage("order/queryListBySkuIds", utils.Struct2MapByJson(queryParam), nil, nil, nil)
|
||||
if err == nil {
|
||||
return utils.Slice2MapSlice(result.([]interface{})), nil
|
||||
err = utils.Map2StructByJson(result, &imgList, false)
|
||||
}
|
||||
return nil, err
|
||||
|
||||
return imgList, err
|
||||
}
|
||||
|
||||
// 分页查询京东到家商品前缀库接口
|
||||
@@ -543,22 +581,12 @@ func (a *API) GetSpuSaleAttr(outSpuId string) (attrList []map[string]interface{}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (a *API) BatchAddSku(paramList []*CreateByUpcParam) (pairs []*CreateByUpcPair, err error) {
|
||||
batchSkuRequestList := make([]map[string]interface{}, len(paramList))
|
||||
for k, v := range paramList {
|
||||
batchSkuRequestList[k] = map[string]interface{}{
|
||||
"uniqueCode": v.Upc,
|
||||
"outSku": v.OutSkuId,
|
||||
"jdPrice": fmt.Sprintf("%.2f", float32(v.Price)/100),
|
||||
"shopCategoryId": v.ShopCategoryId,
|
||||
"isSale": v.IsSale,
|
||||
}
|
||||
}
|
||||
func (a *API) BatchAddSku(batchSkuRequestList []*CreateByUpcParam) (pairs []*CreateByUpcPair, err error) {
|
||||
result, err := a.AccessAPINoPage("PmsSkuMainService/batchAddSku", map[string]interface{}{
|
||||
"batchSkuRequestList": batchSkuRequestList,
|
||||
}, nil, nil, genNoPageResultParser("code", "result", "detail", "0"))
|
||||
if err == nil {
|
||||
globals.SugarLogger.Debug(utils.Format4Output(result, false))
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(result, false))
|
||||
// todo 这个API在找不到UPC创建失败时,code也是0,底层不能判断失败
|
||||
if result2, ok := result.([]interface{}); ok && len(result2) > 0 {
|
||||
detail := utils.Slice2MapSlice(result2)
|
||||
|
||||
@@ -58,7 +58,11 @@ func TestBatchUpdateOutSkuId(t *testing.T) {
|
||||
|
||||
func TestQuerySkuInfos(t *testing.T) {
|
||||
pageSize := 20
|
||||
result, totalCount, err := api.QuerySkuInfos("一个高级商品", 0, 0, pageSize, true)
|
||||
result, totalCount, err := api.QuerySkuInfos(&QuerySkuParam{
|
||||
IsFilterDel: IsFilterDelTrue,
|
||||
})
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
t.Log(totalCount)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -73,7 +77,10 @@ func TestQueryListBySkuIds(t *testing.T) {
|
||||
2018806493,
|
||||
2018805873,
|
||||
}
|
||||
result, err := api.QueryListBySkuIds(ids, nil)
|
||||
result, err := api.QueryListBySkuIds(&QueryListBySkuIdsParam{
|
||||
SkuIDs: ids,
|
||||
})
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -152,10 +159,10 @@ func TestGetSpuSaleAttr(t *testing.T) {
|
||||
func TestBatchAddSku(t *testing.T) {
|
||||
paramList := []*CreateByUpcParam{
|
||||
&CreateByUpcParam{
|
||||
Upc: "6948939649102",
|
||||
OutSkuId: "50001",
|
||||
Price: 213,
|
||||
ShopCategoryId: 4247719,
|
||||
UniqueUpc: "6948939649102",
|
||||
OutSku: "50001",
|
||||
JdPrice: "2.13",
|
||||
ShopCategoryID: 4247719,
|
||||
IsSale: true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -29,6 +29,19 @@ const (
|
||||
KeyStandByPhone = "standByPhone"
|
||||
)
|
||||
|
||||
const (
|
||||
CarrierNoCrowdSourcing = 9966 // 众包
|
||||
CarrierNoSelfDelivery = 2938 // 自送
|
||||
CarrierNoSelfTake = 9999 // 到店自提
|
||||
)
|
||||
|
||||
const (
|
||||
CoordinateTypeGoogle = 1 // 谷歌
|
||||
CoordinateTypeBaidu = 2 // 百度
|
||||
CoordinateTypeAutonavi = 3 // 高德
|
||||
CoordinateTypeTencent = 4 // 腾讯
|
||||
)
|
||||
|
||||
type CreateShopResult struct {
|
||||
DeliveryRangeType int `json:"deliveryRangeType"`
|
||||
CoordinatePoints string `json:"coordinatePoints"`
|
||||
@@ -44,6 +57,165 @@ type CityInfo struct {
|
||||
Yn int `json:"yn"`
|
||||
}
|
||||
|
||||
type OpStoreParams struct {
|
||||
// 以下可用于修改(及查询)
|
||||
StationNo string `json:"stationNo"` // 强制参数,主键
|
||||
StationName string `json:"stationName,omitempty"`
|
||||
OutSystemID string `json:"outSystemId,omitempty"`
|
||||
Mobile string `json:"mobile,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
Lat float64 `json:"lat,omitempty"`
|
||||
Lng float64 `json:"lng,omitempty"`
|
||||
City int `json:"city,omitempty"`
|
||||
County int `json:"county,omitempty"`
|
||||
StationAddress string `json:"stationAddress,omitempty"`
|
||||
Operator string `json:"operator"` // 返回值无
|
||||
ServiceTimeEnd1 int `json:"serviceTimeEnd1,omitempty"`
|
||||
ServiceTimeStart1 int `json:"serviceTimeStart1,omitempty"`
|
||||
ServiceTimeEnd2 int `json:"serviceTimeEnd2,omitempty"`
|
||||
ServiceTimeStart2 int `json:"serviceTimeStart2,omitempty"`
|
||||
DeliveryRangeType int8 `json:"deliveryRangeType,omitempty"` // 返回值无,划分配送服务范围的类型(3、圆心半径、2、不规则多边形(手动画范围))。若更新此字段需传完整值。
|
||||
CoordinateType int `json:"coordinateType,omitempty"` // 返回值无,使用的地图类型(1,谷歌), (2,百度), (3,高德), (4,腾讯)
|
||||
DeliveryRangeRadius int `json:"deliveryRangeRadius,omitempty"` // 返回值无,时效服务范围半径(单位:米)(如果服务范围为类型3的话,该字段有值)
|
||||
CoordinatePoints string `json:"coordinatePoints,omitempty"` // 返回值无,坐标点集合(如果服务范围为类型2的话,该字段有值),每个点以:经度,纬度 的格式表示,用“;”隔开多个点;对于腾讯地图、谷歌地图和高德地图,整个coordinatePoints的长度必须小于2k;对于百度地图,整个coordinatePoints的长度必须小于1k
|
||||
CloseStatus int `json:"closeStatus"` // 0是有意义的值,所以不能是omitempty
|
||||
StoreNotice string `json:"storeNotice,omitempty"`
|
||||
StandByPhone string `json:"standByPhone,omitempty"`
|
||||
}
|
||||
|
||||
type StoreDetail struct {
|
||||
// 以下可用于修改(及查询)
|
||||
StationNo string `json:"stationNo"` // 强制参数,主键
|
||||
StationName string `json:"stationName,omitempty"`
|
||||
OutSystemID string `json:"outSystemId,omitempty"`
|
||||
Mobile string `json:"mobile,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
Lat float64 `json:"lat,omitempty"`
|
||||
Lng float64 `json:"lng,omitempty"`
|
||||
City int `json:"city,omitempty"`
|
||||
County int `json:"county,omitempty"`
|
||||
StationAddress string `json:"stationAddress,omitempty"`
|
||||
// Operator string `json:"operator"` // 返回值无
|
||||
ServiceTimeEnd1 int `json:"serviceTimeEnd1,omitempty"`
|
||||
ServiceTimeStart1 int `json:"serviceTimeStart1,omitempty"`
|
||||
ServiceTimeEnd2 int `json:"serviceTimeEnd2,omitempty"`
|
||||
ServiceTimeStart2 int `json:"serviceTimeStart2,omitempty"`
|
||||
// DeliveryRangeType int8 `json:"deliveryRangeType,omitempty"` // 返回值无,划分配送服务范围的类型(3、圆心半径、2、不规则多边形(手动画范围))。若更新此字段需传完整值。
|
||||
// CoordinateType int `json:"coordinateType,omitempty"` // 返回值无,使用的地图类型(1,谷歌), (2,百度), (3,高德), (4,腾讯)
|
||||
// DeliveryRangeRadius int `json:"deliveryRangeRadius,omitempty"` // 返回值无,时效服务范围半径(单位:米)(如果服务范围为类型3的话,该字段有值)
|
||||
// CoordinatePoints string `json:"coordinatePoints,omitempty"` // 返回值无,坐标点集合(如果服务范围为类型2的话,该字段有值),每个点以:经度,纬度 的格式表示,用“;”隔开多个点;对于腾讯地图、谷歌地图和高德地图,整个coordinatePoints的长度必须小于2k;对于百度地图,整个coordinatePoints的长度必须小于1k
|
||||
CloseStatus int `json:"closeStatus"` // 0是有意义的值,所以不能是omitempty
|
||||
StoreNotice string `json:"storeNotice,omitempty"`
|
||||
StandByPhone string `json:"standByPhone,omitempty"`
|
||||
|
||||
// 以下仅用于查询
|
||||
AllowRangeOptimized int `json:"allowRangeOptimized"`
|
||||
CacheKey4StoreList string `json:"cacheKey4StoreList"`
|
||||
CarrierNo int `json:"carrierNo"`
|
||||
CityName string `json:"cityName"`
|
||||
Coordinate string `json:"coordinate"`
|
||||
CoordinateAddress string `json:"coordinateAddress"`
|
||||
CountyName string `json:"countyName"`
|
||||
CreatePin string `json:"createPin"`
|
||||
CreateTime *utils.JavaDate `json:"createTime"`
|
||||
ID int64 `json:"id"`
|
||||
IndustryTag int `json:"industryTag"`
|
||||
InnerNoStatus int `json:"innerNoStatus"`
|
||||
IsAutoOrder int `json:"isAutoOrder"` // 是否自动接单,0:是1:否
|
||||
IsMembership int `json:"isMembership"`
|
||||
IsNoPaper int `json:"isNoPaper"`
|
||||
OnlineTime *utils.JavaDate `json:"onlineTime"`
|
||||
OrderAging int `json:"orderAging"`
|
||||
OrderNoticeType int `json:"orderNoticeType"`
|
||||
PreWarehouse int `json:"preWarehouse"`
|
||||
Province int `json:"province"`
|
||||
ProvinceName string `json:"provinceName"`
|
||||
QualifyStatus int `json:"qualifyStatus"`
|
||||
RegularFlag int `json:"regularFlag"`
|
||||
StationDeliveryStatus int `json:"stationDeliveryStatus"`
|
||||
SupportInvoice int `json:"supportInvoice"`
|
||||
SupportOfflinePurchase int `json:"supportOfflinePurchase"`
|
||||
TestMark int `json:"testMark"`
|
||||
TimeAmType int `json:"timeAmType"`
|
||||
TimePmType int `json:"timePmType"`
|
||||
Ts *utils.JavaDate `json:"ts"`
|
||||
UpdatePin string `json:"updatePin"`
|
||||
UpdateTime *utils.JavaDate `json:"updateTime"`
|
||||
VenderID string `json:"venderId"`
|
||||
VenderName string `json:"venderName"`
|
||||
WareType int `json:"wareType"`
|
||||
WhiteDelivery bool `json:"whiteDelivery"`
|
||||
Yn int8 `json:"yn"` // 门店状态,0启用,1禁用
|
||||
}
|
||||
|
||||
type OrderProdCommentVo struct {
|
||||
CreatePin string `json:"createPin"`
|
||||
CreateTime *utils.JavaDate `json:"createTime"`
|
||||
ID int64 `json:"id"`
|
||||
IsPraise int `json:"isPraise"`
|
||||
Score int `json:"score"`
|
||||
ScoreLevel int `json:"scoreLevel"`
|
||||
SkuID int64 `json:"skuId"`
|
||||
SkuName string `json:"skuName"`
|
||||
UpdatePin string `json:"updatePin"`
|
||||
UpdateTime *utils.JavaDate `json:"updateTime"`
|
||||
Yn int8 `json:"yn"`
|
||||
}
|
||||
|
||||
type OrderCommentInfo struct {
|
||||
AppVersion string `json:"appVersion"`
|
||||
CreatePin string `json:"createPin"`
|
||||
CreateTime *utils.JavaDate `json:"createTime"`
|
||||
DeliveryCarrierNo string `json:"deliveryCarrierNo"`
|
||||
DeliveryConfirmTime *utils.JavaDate `json:"deliveryConfirmTime"`
|
||||
DeliveryConfirmTime2 *utils.JavaDate `json:"deliveryConfirmTime2"`
|
||||
DeliveryDifTime int `json:"deliveryDifTime"`
|
||||
DeliveryDifTime2 int `json:"deliveryDifTime2"`
|
||||
DeliveryManNo string `json:"deliveryManNo"`
|
||||
DocID interface{} `json:"docId"`
|
||||
ID int64 `json:"id"`
|
||||
IsUpdate int `json:"isUpdate"`
|
||||
OrderID int64 `json:"orderId"`
|
||||
OrderProdCommentVoList []*OrderProdCommentVo `json:"orderProdCommentVoList"`
|
||||
OrderType int `json:"orderType"`
|
||||
OrgCode int `json:"orgCode"`
|
||||
OrgCommentContent string `json:"orgCommentContent"`
|
||||
OrgCommentStatus int `json:"orgCommentStatus"`
|
||||
OrgCommentTime *utils.JavaDate `json:"orgCommentTime"`
|
||||
OrgName string `json:"orgName"`
|
||||
Score3 int `json:"score3"`
|
||||
Score3Content string `json:"score3Content"`
|
||||
Score4 int `json:"score4"`
|
||||
Score4Content string `json:"score4Content"`
|
||||
ScoreLevel int `json:"scoreLevel"`
|
||||
StoreID int64 `json:"storeId"`
|
||||
StoreName string `json:"storeName"`
|
||||
Tags []string `json:"tags"`
|
||||
TagsKey []string `json:"tagsKey"`
|
||||
UpdatePin string `json:"updatePin"`
|
||||
UpdateTime *utils.JavaDate `json:"updateTime"`
|
||||
VenderTageKey []string `json:"venderTageKey"`
|
||||
VenderTags []string `json:"venderTags"`
|
||||
Yn int8 `json:"yn"`
|
||||
}
|
||||
|
||||
type StoreDeliveryRange struct {
|
||||
Adresses string `json:"adresses"`
|
||||
CreatePin string `json:"createPin"`
|
||||
CreateTime *utils.JavaDate `json:"createTime"`
|
||||
DeliveryRange string `json:"deliveryRange"`
|
||||
DeliveryRangeRadius int `json:"deliveryRangeRadius"`
|
||||
DeliveryRangeType int `json:"deliveryRangeType"`
|
||||
DeliveryServiceType int `json:"deliveryServiceType"`
|
||||
ID int `json:"id"`
|
||||
StationNo string `json:"stationNo"`
|
||||
Ts *utils.JavaDate `json:"ts"`
|
||||
UpdatePin string `json:"updatePin"`
|
||||
UpdateTime *utils.JavaDate `json:"updateTime"`
|
||||
VenderID string `json:"venderId"`
|
||||
Yn int8 `json:"yn"`
|
||||
}
|
||||
|
||||
func (a *API) GetAllCities() (cities []*CityInfo, err error) {
|
||||
result, err := a.AccessAPINoPage("address/allcities", nil, nil, nil, genNoPageResultParser("code", "msg", "result", "0"))
|
||||
if err == nil {
|
||||
@@ -69,23 +241,9 @@ func (a *API) GetStationsByVenderId() ([]string, error) {
|
||||
|
||||
// 新增不带资质的门店信息接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=93acef27c3aa4d8286d5c8c26b493629
|
||||
func (a *API) CreateStore(stationName, phone string, city, county int, stationAddress, userName string, serviceTimeStart1, serviceTimeEnd1 int, lng, lat float64, deliveryRangeType, coordinateType int, standByPhone string, addParams map[string]interface{}) (*CreateShopResult, error) {
|
||||
params := map[string]interface{}{
|
||||
KeyStationName: stationName,
|
||||
KeyPhone: phone,
|
||||
KeyCity: city,
|
||||
KeyCounty: county,
|
||||
KeyStationAddress: stationAddress,
|
||||
KeyOperator: utils.GetAPIOperator(userName),
|
||||
KeyServiceTimeStart1: serviceTimeStart1,
|
||||
KeyServiceTimeEnd2: serviceTimeEnd1,
|
||||
KeyLng: lng,
|
||||
KeyLat: lat,
|
||||
KeyDeliveryRangeType: deliveryRangeType,
|
||||
KeyCoordinateType: coordinateType,
|
||||
KeyStandByPhone: standByPhone,
|
||||
}
|
||||
result, err := a.AccessAPINoPage("store/createStore", utils.MergeMaps(params, addParams), nil, nil, func(data map[string]interface{}) (interface{}, error) {
|
||||
func (a *API) CreateStore(createParams *OpStoreParams) (*CreateShopResult, error) {
|
||||
createParams.Operator = utils.GetAPIOperator(createParams.Operator)
|
||||
result, err := a.AccessAPINoPage("store/createStore", utils.Struct2MapByJson(createParams), nil, nil, func(data map[string]interface{}) (interface{}, error) {
|
||||
innerCode := data["code"].(string)
|
||||
if data["code"] == "0" {
|
||||
mapData := data["data"].(map[string]interface{})
|
||||
@@ -102,37 +260,66 @@ func (a *API) CreateStore(stationName, phone string, city, county int, stationAd
|
||||
|
||||
// 根据到家门店编码查询门店基本信息接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=4c48e347027146d5a103e851055cb1a7
|
||||
func (a *API) GetStoreInfoByStationNo(storeNo string) (map[string]interface{}, error) {
|
||||
// func (a *API) GetStoreInfoByStationNo(storeNo string) (map[string]interface{}, error) {
|
||||
// result, err := a.AccessAPINoPage("storeapi/getStoreInfoByStationNo", utils.Params2Map("StoreNo", storeNo), nil, nil, nil)
|
||||
// if err == nil {
|
||||
// return result.(map[string]interface{}), nil
|
||||
// }
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
func (a *API) GetStoreInfoByStationNo2(storeNo string) (storeDetail *StoreDetail, err error) {
|
||||
result, err := a.AccessAPINoPage("storeapi/getStoreInfoByStationNo", utils.Params2Map("StoreNo", storeNo), nil, nil, nil)
|
||||
if err == nil {
|
||||
return result.(map[string]interface{}), nil
|
||||
err = utils.Map2StructByJson(result, &storeDetail, false)
|
||||
}
|
||||
return nil, err
|
||||
return storeDetail, err
|
||||
}
|
||||
|
||||
// 修改门店基础信息接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=2600369a456446f0921e918f3d15e96a
|
||||
func (a *API) UpdateStoreInfo4Open(storeNo, userName string, addParams map[string]interface{}) error {
|
||||
jdParams := map[string]interface{}{
|
||||
"stationNo": storeNo,
|
||||
"operator": utils.GetAPIOperator(userName),
|
||||
// func (a *API) UpdateStoreInfo4Open(storeNo, userName string, addParams map[string]interface{}) error {
|
||||
// jdParams := map[string]interface{}{
|
||||
// "stationNo": storeNo,
|
||||
// "operator": utils.GetAPIOperator(userName),
|
||||
// }
|
||||
// jdParams = utils.MergeMaps(jdParams, addParams)
|
||||
// _, err := a.AccessAPINoPage("store/updateStoreInfo4Open", jdParams, nil, nil, nullResultParser)
|
||||
// return err
|
||||
// }
|
||||
|
||||
func (a *API) UpdateStoreInfo4Open2(updateParams *OpStoreParams, modifyCloseStatus bool) (err error) {
|
||||
updateParams.Operator = utils.GetAPIOperator(updateParams.Operator)
|
||||
mapData := utils.Struct2MapByJson(updateParams)
|
||||
if !modifyCloseStatus {
|
||||
delete(mapData, "closeStatus")
|
||||
}
|
||||
jdParams = utils.MergeMaps(jdParams, addParams)
|
||||
_, err := a.AccessAPINoPage("store/updateStoreInfo4Open", jdParams, nil, nil, nullResultParser)
|
||||
_, err = a.AccessAPINoPage("store/updateStoreInfo4Open", mapData, nil, nil, nullResultParser)
|
||||
return err
|
||||
}
|
||||
|
||||
// 根据订单号查询商家门店评价信息接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=bd23397725bb4e74b69e2f2fa1c88d43
|
||||
func (a *API) GetCommentByOrderId(orderId int64) (map[string]interface{}, error) {
|
||||
// func (a *API) GetCommentByOrderId(orderId int64) (map[string]interface{}, error) {
|
||||
// jdParams := map[string]interface{}{
|
||||
// "orderId": orderId,
|
||||
// }
|
||||
// result, err := a.AccessAPINoPage("commentOutApi/getCommentByOrderId", jdParams, nil, nil, genNoPageResultParser("code", "msg", "result", "200"))
|
||||
// if err == nil {
|
||||
// return result.(map[string]interface{}), nil
|
||||
// }
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
func (a *API) GetCommentByOrderId2(orderId int64) (orderComment *OrderCommentInfo, err error) {
|
||||
jdParams := map[string]interface{}{
|
||||
"orderId": orderId,
|
||||
}
|
||||
result, err := a.AccessAPINoPage("commentOutApi/getCommentByOrderId", jdParams, nil, nil, genNoPageResultParser("code", "msg", "result", "200"))
|
||||
if err == nil {
|
||||
return result.(map[string]interface{}), nil
|
||||
err = utils.Map2StructByJson(result, &orderComment, false)
|
||||
}
|
||||
return nil, err
|
||||
return orderComment, err
|
||||
}
|
||||
|
||||
// 商家门店评价信息回复接口
|
||||
@@ -169,15 +356,26 @@ func (a *API) UpdateStoreConfig4Open(stationNo string, isAutoOrder bool) (bool,
|
||||
|
||||
// 获取门店配送范围接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=8f6d0ac75d734c68bf5bd2a09f376a78
|
||||
func (a *API) GetDeliveryRangeByStationNo(stationNo string) (map[string]interface{}, error) {
|
||||
// func (a *API) GetDeliveryRangeByStationNo(stationNo string) (map[string]interface{}, error) {
|
||||
// jdParams := map[string]interface{}{
|
||||
// "stationNo": stationNo,
|
||||
// }
|
||||
// result, err := a.AccessAPINoPage("store/getDeliveryRangeByStationNo", jdParams, nil, nil, nil)
|
||||
// if err == nil {
|
||||
// return result.(map[string]interface{}), nil
|
||||
// }
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
func (a *API) GetDeliveryRangeByStationNo2(stationNo string) (deliveryRange *StoreDeliveryRange, err error) {
|
||||
jdParams := map[string]interface{}{
|
||||
"stationNo": stationNo,
|
||||
}
|
||||
result, err := a.AccessAPINoPage("store/getDeliveryRangeByStationNo", jdParams, nil, nil, nil)
|
||||
if err == nil {
|
||||
return result.(map[string]interface{}), nil
|
||||
err = utils.Map2StructByJson(result, &deliveryRange, false)
|
||||
}
|
||||
return nil, err
|
||||
return deliveryRange, err
|
||||
}
|
||||
|
||||
// 私有函数
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package jdapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -36,9 +40,9 @@ type CorporationInfo struct {
|
||||
EconKind string `json:"econ_kind"`
|
||||
EndDate string `json:"end_date"`
|
||||
TermEnd string `json:"term_end"`
|
||||
NeedID bool `json:"needID"`
|
||||
Address string `json:"address"`
|
||||
Partners []struct {
|
||||
// NeedID bool `json:"needID"`
|
||||
Address string `json:"address"`
|
||||
Partners []struct {
|
||||
IdentifyType string `json:"identify_type"`
|
||||
ShouldCapiItems []interface{} `json:"should_capi_items"`
|
||||
StockType string `json:"stock_type"`
|
||||
@@ -136,14 +140,108 @@ type PageShopInfo struct {
|
||||
StoreShareURL string `json:"storeShareUrl"`
|
||||
}
|
||||
|
||||
var (
|
||||
monthSaleNumReg = regexp.MustCompile(`(\d+)([千|万])`)
|
||||
type PageSku struct {
|
||||
ButtonEnable bool `json:"buttonEnable"`
|
||||
CatID string `json:"catId"`
|
||||
FixedStatus bool `json:"fixedStatus"`
|
||||
FuncIndicatins string `json:"funcIndicatins"`
|
||||
H5SwichItem struct {
|
||||
IsLeadApp bool `json:"isLeadApp"`
|
||||
} `json:"h5SwichItem"`
|
||||
HasSaleAttr bool `json:"hasSaleAttr"`
|
||||
IconType int `json:"iconType"`
|
||||
Image []*SkuPageImg `json:"image"`
|
||||
InCartCount int `json:"inCartCount"`
|
||||
IsInScope bool `json:"isInScope"`
|
||||
IsRemind bool `json:"isRemind"`
|
||||
MarkingPrice string `json:"markingPrice"`
|
||||
Name string `json:"name"`
|
||||
OrgCode string `json:"orgCode"`
|
||||
Prescription bool `json:"prescription"`
|
||||
PriceUnit string `json:"priceUnit"`
|
||||
ProductComment struct {
|
||||
CommentNum string `json:"commentNum"`
|
||||
GoodRate float64 `json:"goodRate"`
|
||||
GoodRating string `json:"goodRating"`
|
||||
HasMore bool `json:"hasMore"`
|
||||
TotalScore string `json:"totalScore"`
|
||||
} `json:"productComment"`
|
||||
ProductInfoType int `json:"productInfoType"`
|
||||
ProductType int `json:"productType"`
|
||||
ProductTypeEnum string `json:"productTypeEnum"`
|
||||
ShareProductURL string `json:"shareProductUrl"`
|
||||
ShowState int `json:"showState"`
|
||||
ShowStateEnum string `json:"showStateEnum"`
|
||||
ShowStateName string `json:"showStateName"`
|
||||
ShowTimLine bool `json:"showTimLine"`
|
||||
SkuID int64 `json:"skuId"`
|
||||
SkuPriceVO struct {
|
||||
BasicPrice string `json:"basicPrice"`
|
||||
MkPrice string `json:"mkPrice"`
|
||||
Promotion int `json:"promotion"`
|
||||
RealTimePrice string `json:"realTimePrice"`
|
||||
SkuID string `json:"skuId"`
|
||||
} `json:"skuPriceVO"`
|
||||
Standard string `json:"standard"`
|
||||
StoreInfo struct {
|
||||
Show bool `json:"show"`
|
||||
StoreID string `json:"storeId"`
|
||||
} `json:"storeInfo"`
|
||||
Subtitle string `json:"subtitle"`
|
||||
Tags []string `json:"tags"`
|
||||
UserActionSku string `json:"userActionSku"`
|
||||
VenderID string `json:"venderId"`
|
||||
}
|
||||
|
||||
const (
|
||||
QualifyTypeCompany = "25" // 营业执照
|
||||
QualifyTypePerson = "22" // 身份证,个体工商户要求填
|
||||
QualifyTypeAddInfo = "31" // 附加信息,如果身份证是长期有效,要求身份证背面信息
|
||||
|
||||
SaveQualifyActionTypeCommit = 0 // 提交
|
||||
SaveQualifyActionTypeSave = 1 // 暂时保存
|
||||
)
|
||||
|
||||
func (a *API) AccessStorePage(fullURL string, params map[string]interface{}, isPost bool) (retVal map[string]interface{}, err error) {
|
||||
type QualifyItem struct {
|
||||
QualifyURL string `json:"qualifyUrl"`
|
||||
QualifyType string `json:"qualifyType"`
|
||||
QualifyExpireForever int `json:"qualifyExpireForever"` // 0:永久有性,1:非永久有效(需要填QualifyExpireEnd)
|
||||
QualifyExpireStart string `json:"qualifyExpireStart"`
|
||||
QualifyExpireEnd string `json:"qualifyExpireEnd,omitempty"`
|
||||
QualifyName string `json:"qualifyName,omitempty"`
|
||||
QualifyOwner string `json:"qualifyOwner,omitempty"`
|
||||
LicenceType string `json:"licenceType,omitempty"` // -1
|
||||
QualifyNumber string `json:"qualifyNumber,omitempty"`
|
||||
QualifyAddress string `json:"qualifyAddress,omitempty"`
|
||||
LicenceName string `json:"licenceName,omitempty"`
|
||||
EconKind string `json:"econKind,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
var (
|
||||
monthSaleNumReg = regexp.MustCompile(`(\d+)([千|万])`)
|
||||
pageExceedLimitCodes = map[string]int{
|
||||
"403": 1,
|
||||
}
|
||||
pageCanRetryCodes = map[string]int{}
|
||||
)
|
||||
|
||||
const (
|
||||
KeyImgData = "imgData"
|
||||
KeyImgName = "imgName"
|
||||
|
||||
ResultKeyData = "data"
|
||||
ResultKeyResult = "result"
|
||||
)
|
||||
|
||||
func (a *API) AccessStorePage2(fullURL string, params map[string]interface{}, isPost bool, resultKey string) (retVal interface{}, err error) {
|
||||
if a.GetCookieCount() == 0 {
|
||||
return nil, fmt.Errorf("需要设置Store Cookie才能使用此方法")
|
||||
}
|
||||
imgData := params[KeyImgData]
|
||||
if imgData != nil {
|
||||
delete(params, KeyImgData)
|
||||
}
|
||||
err = platformapi.AccessPlatformAPIWithRetry(a.client,
|
||||
func() *http.Request {
|
||||
var request *http.Request
|
||||
@@ -151,8 +249,26 @@ func (a *API) AccessStorePage(fullURL string, params map[string]interface{}, isP
|
||||
request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(fullURL, "", params), nil)
|
||||
} else {
|
||||
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(utils.Map2URLValues(params).Encode()))
|
||||
if params[KeyImgName] == nil {
|
||||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
} else {
|
||||
var b bytes.Buffer
|
||||
w := multipart.NewWriter(&b)
|
||||
if fw, err := w.CreateFormFile("uploadFile", params[KeyImgName].(string)); err != nil {
|
||||
panic(err.Error())
|
||||
} else {
|
||||
fw.Write(imgData.([]byte))
|
||||
}
|
||||
for k, v := range params {
|
||||
// baseapi.SugarLogger.Debug(k, " ", v)
|
||||
w.WriteField(k, url.QueryEscape(fmt.Sprint(v)))
|
||||
}
|
||||
w.Close()
|
||||
// b.WriteString(utils.Map2URLValues(params).Encode())
|
||||
request, _ = http.NewRequest(http.MethodPost, fullURL, &b)
|
||||
request.Header.Set("Content-Type", w.FormDataContentType())
|
||||
}
|
||||
request.Header.Set("charset", "UTF-8")
|
||||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -166,15 +282,20 @@ func (a *API) AccessStorePage(fullURL string, params map[string]interface{}, isP
|
||||
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
|
||||
}
|
||||
retVal = jsonResult1
|
||||
code := jsonResult1["code"].(string)
|
||||
code, ok := jsonResult1["code"].(string)
|
||||
if !ok {
|
||||
return platformapi.ErrLevelGeneralFail, utils.NewErrorCode(utils.Format4Output(jsonResult1, true), "999")
|
||||
}
|
||||
if code == ResponseCodeSuccess {
|
||||
retVal, _ = jsonResult1["result"].(map[string]interface{})
|
||||
if resultKey != "" {
|
||||
retVal = jsonResult1[resultKey]
|
||||
}
|
||||
return platformapi.ErrLevelSuccess, nil
|
||||
}
|
||||
newErr := utils.NewErrorCode(jsonResult1["msg"].(string), code)
|
||||
if _, ok := exceedLimitCodes[code]; ok {
|
||||
if _, ok := pageExceedLimitCodes[code]; ok {
|
||||
return platformapi.ErrLevelExceedLimit, newErr
|
||||
} else if _, ok := canRetryCodes[code]; ok {
|
||||
} else if _, ok := pageCanRetryCodes[code]; ok {
|
||||
return platformapi.ErrLevelRecoverableErr, newErr
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("jd AccessStorePage failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
|
||||
@@ -184,6 +305,14 @@ func (a *API) AccessStorePage(fullURL string, params map[string]interface{}, isP
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func (a *API) AccessStorePage(fullURL string, params map[string]interface{}, isPost bool) (retVal map[string]interface{}, err error) {
|
||||
result, err := a.AccessStorePage2(fullURL, params, isPost, ResultKeyResult)
|
||||
if err == nil {
|
||||
retVal, _ = result.(map[string]interface{})
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func (a *API) GetRealMobile4Order(orderId, stationNo string) (mobile string, err error) {
|
||||
retVal, err := a.GetStoreOrderInfo(orderId, stationNo)
|
||||
if err == nil {
|
||||
@@ -202,7 +331,7 @@ func (a *API) GetStoreOrderInfo(orderId, stationNo string) (storeOrderInfo map[s
|
||||
if stationNo != "" {
|
||||
params["stationNo"] = stationNo
|
||||
}
|
||||
retVal, err := a.AccessStorePage("http://store.jddj.com/order/newManager/search", params, false)
|
||||
retVal, err := a.AccessStorePage("http://order.jddj.com/order/newManager/search", params, false)
|
||||
// baseapi.SugarLogger.Debug(utils.Format4Output(retVal, false))
|
||||
if err == nil {
|
||||
newOrderinfoMains := retVal["newOrderinfoMains"].(map[string]interface{})
|
||||
@@ -229,7 +358,7 @@ func (a *API) GetStoreOrderInfoList(fromTime, toTime string) (storeOrderList []m
|
||||
|
||||
for {
|
||||
params["pageNo"] = pageNo
|
||||
retVal, err := a.AccessStorePage("http://store.jddj.com/order/newManager/tabQuery/all", params, false)
|
||||
retVal, err := a.AccessStorePage("http://order.jddj.com/order/newManager/tabQuery/all", params, false)
|
||||
// baseapi.SugarLogger.Debug(utils.Format4Output(retVal, false))
|
||||
if err == nil {
|
||||
newOrderinfoMains := retVal["newOrderinfoMains"].(map[string]interface{})
|
||||
@@ -246,7 +375,7 @@ func (a *API) GetStoreOrderInfoList(fromTime, toTime string) (storeOrderList []m
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (a *API) GetSkuPageInfo(skuId int64) (skuPageInfo map[string]interface{}, err error) {
|
||||
func (a *API) GetSkuPageInfo(skuId int64) (skuPageInfo *PageSku, err error) {
|
||||
skuIDMap := map[string]interface{}{
|
||||
"skuId": utils.Int64ToStr(skuId),
|
||||
"storeId": "0",
|
||||
@@ -258,14 +387,17 @@ func (a *API) GetSkuPageInfo(skuId int64) (skuPageInfo map[string]interface{}, e
|
||||
"body": utils.Format4Output(skuIDMap, true),
|
||||
}
|
||||
|
||||
skuPageInfo, err = a.AccessStorePage("https://daojia.jd.com/client", params, false)
|
||||
result, err := a.AccessStorePage("https://daojia.jd.com/client", params, false)
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(result, &skuPageInfo, false)
|
||||
}
|
||||
return skuPageInfo, err
|
||||
}
|
||||
|
||||
func (a *API) GetSkuPageImageInfo(skuId int64) (imgList []*SkuPageImg, err error) {
|
||||
skuPageInfo, err := a.GetSkuPageInfo(skuId)
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(skuPageInfo["image"], &imgList, false)
|
||||
imgList = skuPageInfo.Image
|
||||
}
|
||||
return imgList, err
|
||||
}
|
||||
@@ -346,3 +478,47 @@ func MonthSaleNum2Int(monthSaleNumStr string) (monthSaleNum int) {
|
||||
}
|
||||
return monthSaleNum
|
||||
}
|
||||
|
||||
func (a *API) StoreUploadImg(imgFileName string, imgBin []byte) (imgURL string, err error) {
|
||||
result, err := a.AccessStorePage2("https://sta-store.jddj.com/store/uploadImg.json", map[string]interface{}{
|
||||
KeyImgData: imgBin,
|
||||
KeyImgName: imgFileName,
|
||||
}, true, ResultKeyData)
|
||||
if err == nil {
|
||||
imgURL = result.(string)
|
||||
}
|
||||
return imgURL, err
|
||||
}
|
||||
|
||||
func (a *API) StoreUploadImgByURL(inImgURL string) (imgURL string, err error) {
|
||||
response, err := http.Get(inImgURL)
|
||||
if err == nil {
|
||||
defer func() {
|
||||
response.Body.Close()
|
||||
}()
|
||||
if response.StatusCode == http.StatusOK {
|
||||
bodyData, err2 := ioutil.ReadAll(response.Body)
|
||||
if err = err2; err == nil {
|
||||
imgName := utils.GetUUID()
|
||||
if lastSlashIndex := strings.LastIndex(inImgURL, "/"); lastSlashIndex >= 0 {
|
||||
imgName = inImgURL[lastSlashIndex+1:]
|
||||
}
|
||||
return a.StoreUploadImg(imgName, bodyData)
|
||||
}
|
||||
} else {
|
||||
err = platformapi.ErrHTTPCodeIsNot200
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
func (a *API) SaveQualify(stationNo string, actionType int, qualifyList []*QualifyItem) (err error) {
|
||||
_, err = a.AccessStorePage2("https://sta-store.jddj.com/store/saveQualify.o2o", map[string]interface{}{
|
||||
"stationNo": stationNo,
|
||||
"actionType": actionType,
|
||||
"qualifyList": utils.Format4Output(qualifyList, true),
|
||||
"type": 1,
|
||||
"degrade": "no",
|
||||
}, true, "")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
)
|
||||
|
||||
func TestGetRealMobileNumber4Order(t *testing.T) {
|
||||
orderId := "910170516000941"
|
||||
desiredMobile := "13398196274"
|
||||
mobile, err := api.GetRealMobile4Order(orderId, "")
|
||||
orderId := "921823424000122"
|
||||
desiredMobile := "13722455105"
|
||||
mobile, err := api.GetRealMobile4Order(orderId, "11893205")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -21,8 +21,8 @@ func TestGetRealMobileNumber4Order(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetStoreOrderInfo(t *testing.T) {
|
||||
orderId := "910170516000941"
|
||||
orderInfo, err := api.GetStoreOrderInfo(orderId, "")
|
||||
orderId := "921823424000122"
|
||||
orderInfo, err := api.GetStoreOrderInfo(orderId, "11893205")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func TestGetSkuPageImageInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetCorporationInfo(t *testing.T) {
|
||||
imgList, err := api.GetCorporationInfo("", "915101003431062533")
|
||||
imgList, err := api.GetCorporationInfo("", "92330104MA28XPXH5G")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -101,3 +101,91 @@ func TestMonthSaleNum2Int(t *testing.T) {
|
||||
t.Fatalf("num3:%d", num3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreUploadImgByURL(t *testing.T) {
|
||||
outImgURL, err := api.StoreUploadImgByURL("http://image.jxc4.com/940c151db7e396f2ceaec0304597836f.jpg")
|
||||
t.Log(outImgURL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveQualify(t *testing.T) {
|
||||
jsonStr := `
|
||||
[
|
||||
{
|
||||
"qualifyUrl":"http://img30.360buyimg.com/vendersettle/jfs/t1/69834/24/6602/68812/5d4d35fdEaaf373c6/5c1c50e7bb6330e4.jpg",
|
||||
"qualifyType":"25",
|
||||
"qualifyExpireForever":0,
|
||||
"qualifyExpireStart":"2017-09-07 00:00:00",
|
||||
"qualifyName":"刘男",
|
||||
"licenceType":"-1",
|
||||
"qualifyNumber":"92330104MA28XPXH5G",
|
||||
"qualifyAddress":"浙江省杭州市江干区八堡家园5排10号一楼102",
|
||||
"licenceName":"杭州市江干区刘男便利店",
|
||||
"econKind":"个体工商户",
|
||||
"scope":"食品经营(凭有效许可证经营);零售:卷烟、雪茄烟(凭有效许可证经营);批发、零售:日用百货,五金。(依法须经批准的项目,经相关部门批准后方可开展经营活动)"
|
||||
},
|
||||
{
|
||||
"qualifyUrl":"http://img30.360buyimg.com/vendersettle/jfs/t1/58554/26/7134/19343/5d4d3639E57b14138/bcce25e1eac11be8.jpg",
|
||||
"qualifyType":"22",
|
||||
"qualifyExpireForever":1,
|
||||
"qualifyExpireStart":"2013-07-22 16:59:38",
|
||||
"qualifyExpireEnd":"2033-07-22 16:59:50",
|
||||
"qualifyOwner":"刘男",
|
||||
"qualifyNumber":"420621198110303336"
|
||||
},
|
||||
{
|
||||
"qualifyUrl":"",
|
||||
"qualifyType":"33",
|
||||
"qualifyExpireForever":1,
|
||||
"qualifyExpireStart":"",
|
||||
"qualifyExpireEnd":""
|
||||
},
|
||||
{
|
||||
"qualifyUrl":"",
|
||||
"qualifyType":"8",
|
||||
"qualifyExpireForever":1,
|
||||
"qualifyExpireStart":"",
|
||||
"qualifyExpireEnd":""
|
||||
},
|
||||
{
|
||||
"qualifyUrl":"",
|
||||
"qualifyType":"9",
|
||||
"qualifyExpireForever":1,
|
||||
"qualifyExpireStart":"",
|
||||
"qualifyExpireEnd":""
|
||||
},
|
||||
{
|
||||
"qualifyUrl":"",
|
||||
"qualifyType":"10",
|
||||
"qualifyExpireForever":1,
|
||||
"qualifyExpireStart":"",
|
||||
"qualifyExpireEnd":""
|
||||
},
|
||||
{
|
||||
"qualifyUrl":"",
|
||||
"qualifyType":"29",
|
||||
"qualifyExpireForever":1,
|
||||
"qualifyExpireStart":"",
|
||||
"qualifyExpireEnd":""
|
||||
},
|
||||
{
|
||||
"qualifyUrl":"",
|
||||
"qualifyType":"31",
|
||||
"qualifyExpireForever":1,
|
||||
"qualifyExpireStart":"",
|
||||
"qualifyExpireEnd":""
|
||||
}
|
||||
]
|
||||
`
|
||||
var qualityList []*QualifyItem
|
||||
err := utils.UnmarshalUseNumber([]byte(jsonStr), &qualityList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = api.SaveQualify("11902261", SaveQualifyActionTypeSave, qualityList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
const (
|
||||
MaxStoreSkuBatchSize = 50
|
||||
MaxStockQty = 100000000
|
||||
|
||||
MaxAddByStoreAndSkusCount = 30 // 批量置顶商品排序接口的最大个数
|
||||
)
|
||||
|
||||
type SkuPriceInfo struct {
|
||||
@@ -109,7 +111,7 @@ func (a *API) UpdateVendorStationPrice(trackInfo string, outStationNo, stationNo
|
||||
result, err := a.AccessAPINoPage2("venderprice/updateStationPrice", jdParams, nil, nil, genNoPageResultParser("code", "msg", "result", "0"), trackInfo)
|
||||
if result != nil {
|
||||
var err2 error
|
||||
if responseList, err2 = a.handleBatchOpResult(len(skuPriceInfoList), result, "json2"); err2 != nil && err == nil {
|
||||
if responseList, err2 = a.handleBatchOpResult(len(skuPriceInfoList), err, result, "json2"); err2 != nil && err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
@@ -146,18 +148,20 @@ func (a *API) GetStationInfoList(stationNo string, skuIds []int64) (priceInfo []
|
||||
return priceInfo, err
|
||||
}
|
||||
|
||||
func (a *API) handleBatchOpResult(batchCount int, result interface{}, tagName string) (responseList []*StoreSkuBatchUpdateResponse, err error) {
|
||||
if err = utils.Map2Struct(result, &responseList, true, tagName); err == nil {
|
||||
var failedList []*StoreSkuBatchUpdateResponse
|
||||
for _, v := range responseList {
|
||||
if v.Code != 0 {
|
||||
failedList = append(failedList, v)
|
||||
func (a *API) handleBatchOpResult(batchCount int, inErr error, result interface{}, tagName string) (responseList []*StoreSkuBatchUpdateResponse, err error) {
|
||||
if result != nil {
|
||||
if err = utils.Map2Struct(result, &responseList, true, tagName); err == nil {
|
||||
var failedList []*StoreSkuBatchUpdateResponse
|
||||
for _, v := range responseList {
|
||||
if v.Code != 0 {
|
||||
failedList = append(failedList, v)
|
||||
}
|
||||
}
|
||||
if len(failedList) >= batchCount {
|
||||
err = utils.NewErrorCode(string(utils.MustMarshal(failedList)), ResponseCodeAccessFailed, 1) // 此错误基本用不到
|
||||
} else if len(failedList) > 0 { // 部分失败
|
||||
err = utils.NewErrorCode(string(utils.MustMarshal(failedList)), ResponseInnerCodePartialFailed, 1)
|
||||
}
|
||||
}
|
||||
if len(failedList) >= batchCount {
|
||||
err = utils.NewErrorCode(string(utils.MustMarshal(failedList)), ResponseCodeAccessFailed, 1) // 此错误基本用不到
|
||||
} else if len(failedList) > 0 { // 部分失败
|
||||
err = utils.NewErrorCode(string(utils.MustMarshal(failedList)), ResponseInnerCodePartialFailed, 1)
|
||||
}
|
||||
}
|
||||
return responseList, err
|
||||
@@ -181,7 +185,7 @@ func (a *API) BatchUpdateCurrentQtys(trackInfo, outStationNo, stationNo string,
|
||||
result, err := a.AccessAPINoPage2("stock/batchUpdateCurrentQtys", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "data", "0"), trackInfo)
|
||||
if result != nil {
|
||||
var err2 error
|
||||
if responseList, err2 = a.handleBatchOpResult(len(skuStockList), result, ""); err2 != nil && err == nil {
|
||||
if responseList, err2 = a.handleBatchOpResult(len(skuStockList), err, result, ""); err2 != nil && err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
@@ -231,7 +235,7 @@ func (a *API) UpdateVendibility(trackInfo string, listBaseStockCenterRequest []*
|
||||
result, err := a.AccessAPINoPage2("stock/updateVendibility", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "data", "0"), trackInfo)
|
||||
if result != nil {
|
||||
var err2 error
|
||||
if responseList, err2 = a.handleBatchOpResult(len(listBaseStockCenterRequest), result, ""); err2 != nil && err == nil {
|
||||
if responseList, err2 = a.handleBatchOpResult(len(listBaseStockCenterRequest), err, result, ""); err2 != nil && err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
@@ -253,10 +257,11 @@ func (a *API) BatchUpdateVendibility(trackInfo, outStationNo, stationNo string,
|
||||
} else {
|
||||
jdParams["stationNo"] = stationNo
|
||||
}
|
||||
// 此函数在全部失败时,err仍然返回成功
|
||||
result, err := a.AccessAPINoPage2("stock/batchUpdateVendibility", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "data", "0"), trackInfo)
|
||||
if result != nil {
|
||||
var err2 error
|
||||
if responseList, err2 = a.handleBatchOpResult(len(stockVendibilityList), result, ""); err2 != nil && err == nil {
|
||||
if responseList, err2 = a.handleBatchOpResult(len(stockVendibilityList), err, result, ""); err2 != nil && err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
@@ -291,3 +296,14 @@ func (a *API) QueryStockCenter(outStationNo string, skuIds []*SkuIdEntity, userP
|
||||
}
|
||||
return vendibilityResponse, err
|
||||
}
|
||||
|
||||
// 批量置顶商品排序接口
|
||||
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=a7677f1a75984ed3a6ea3d4827f5a6b4
|
||||
func (a *API) AddByStoreAndSkus(stationNo int64, skuIDs []int64) (err error) {
|
||||
jdParams := map[string]interface{}{
|
||||
"storeId": stationNo,
|
||||
"skuIds": skuIDs,
|
||||
}
|
||||
_, err = a.AccessAPINoPage("OrgSortService/addByStoreAndSkus", jdParams, nil, nil, genNoPageResultParser("status", "message", "", "200"))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ import (
|
||||
const (
|
||||
mustExistStoreID = "11053496"
|
||||
mustExistStoreJXID = "2"
|
||||
|
||||
// mustExistStoreID = "11734851"
|
||||
// mustExistStoreJXID = "100118"
|
||||
)
|
||||
|
||||
func TestGetAllCities(t *testing.T) {
|
||||
@@ -39,56 +42,51 @@ func TestGetStationsByVenderId(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetStoreInfoByStationNo(t *testing.T) {
|
||||
result, err := api.GetStoreInfoByStationNo(mustExistStoreID)
|
||||
result, err := api.GetStoreInfoByStationNo2(mustExistStoreID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
outSystemId := result["outSystemId"].(string)
|
||||
if outSystemId != "100285" {
|
||||
baseapi.SugarLogger.Fatalf("outSystemId is not correct, its:%s", outSystemId)
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
if result.OutSystemID != mustExistStoreJXID {
|
||||
baseapi.SugarLogger.Fatalf("outSystemId is not correct, its:%s", result.OutSystemID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateStoreInfo4Open(t *testing.T) {
|
||||
result, err := api.GetStoreInfoByStationNo(mustExistStoreID)
|
||||
result, err := api.GetStoreInfoByStationNo2(mustExistStoreID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
oldAddress := result["stationAddress"].(string)
|
||||
testAddress := oldAddress + "T"
|
||||
addParams := map[string]interface{}{
|
||||
"stationAddress": testAddress,
|
||||
oldAddress := result.StationAddress
|
||||
params := &OpStoreParams{
|
||||
StationNo: mustExistStoreID,
|
||||
Operator: "test",
|
||||
StationAddress: oldAddress + "T",
|
||||
}
|
||||
err = api.UpdateStoreInfo4Open(mustExistStoreID, "test", addParams)
|
||||
err = api.UpdateStoreInfo4Open2(params, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
result, err = api.GetStoreInfoByStationNo(mustExistStoreID)
|
||||
newAddress := result["stationAddress"].(string)
|
||||
if newAddress != testAddress {
|
||||
result, err = api.GetStoreInfoByStationNo2(mustExistStoreID)
|
||||
newAddress := result.StationAddress
|
||||
if newAddress != params.StationAddress {
|
||||
t.Fatalf("address not match, newAddress:%s, oldAddress:%s", newAddress, oldAddress)
|
||||
}
|
||||
|
||||
addParams = map[string]interface{}{
|
||||
"stationAddress": oldAddress,
|
||||
}
|
||||
api.UpdateStoreInfo4Open(mustExistStoreID, "test", addParams)
|
||||
params.StationAddress = oldAddress
|
||||
api.UpdateStoreInfo4Open2(params, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetCommentByOrderId(t *testing.T) {
|
||||
testOrderID := int64(822347450000922)
|
||||
result, err := api.GetCommentByOrderId(testOrderID)
|
||||
testOrderID := int64(922520919000622)
|
||||
result, err := api.GetCommentByOrderId2(testOrderID)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
gotOrderID := utils.MustInterface2Int64(result["orderId"])
|
||||
if gotOrderID != testOrderID {
|
||||
t.Fatalf("GetCommentByOrderId wrong, gotOrderID:%d", gotOrderID)
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
@@ -104,38 +102,38 @@ func TestUpdateStoreConfig4Open(t *testing.T) {
|
||||
t.Fatal(result)
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
result2, err := api.GetStoreInfoByStationNo(testStationNo)
|
||||
result2, err := api.GetStoreInfoByStationNo2(testStationNo)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
isAutoOrder := int(utils.MustInterface2Int64(result2["isAutoOrder"]))
|
||||
isAutoOrder := result2.IsAutoOrder
|
||||
if isAutoOrder != 0 && desiredValue || isAutoOrder == 0 && !desiredValue {
|
||||
t.Fatalf("UpdateStoreConfig4Open failed, isAutoOrder:%d", isAutoOrder)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDeliveryRangeByStationNo(t *testing.T) {
|
||||
const testStoreID = "11738152"
|
||||
result, err := api.GetDeliveryRangeByStationNo(testStoreID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result2, err := api.GetStoreInfoByStationNo(testStoreID)
|
||||
const testStoreID = "11734851"
|
||||
result, err := api.GetDeliveryRangeByStationNo2(testStoreID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
baseapi.SugarLogger.Debug(utils.Format4Output(result, false))
|
||||
baseapi.SugarLogger.Debug(utils.Format4Output(result2, false))
|
||||
deliveryRange := result["deliveryRange"].(string)
|
||||
params := map[string]interface{}{
|
||||
"lng": result2["lng"],
|
||||
"lat": result2["lat"],
|
||||
"coordinateType": 3,
|
||||
"deliveryRangeType": 2,
|
||||
"coordinatePoints": deliveryRange,
|
||||
}
|
||||
err = api.UpdateStoreInfo4Open(testStoreID, "test", params)
|
||||
}
|
||||
|
||||
func TestDisableAutoOrder4AllStores(t *testing.T) {
|
||||
storeIDs, err := api.GetStationsByVenderId()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, storeID := range storeIDs {
|
||||
if storeInfo, err := api.GetStoreInfoByStationNo2(storeID); err == nil {
|
||||
if storeInfo.Yn == 0 && storeInfo.IsAutoOrder == 0 {
|
||||
t.Log(storeID)
|
||||
api.UpdateStoreConfig4Open(storeID, false)
|
||||
}
|
||||
t.Log(utils.Format4Output(storeInfo, false))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func init() {
|
||||
// prod
|
||||
// api = New("3c0a05d464c247c19d7ec13accc78605", "b1M}9?:sTbsB[OF2gNORnN(|(iy9rB8(`7]|[wGLnbmt`evfM>E:A90DjHAW:UPE")
|
||||
|
||||
api.SetCookie("token", "0seqGSJnhbr4XJ0EaIQL6CoOpnaV1ErgS42uOlzNXYIX7PeuLuyCFQQZKKWGExJ7IMTQQQDe5H6YMmVFnxjCkw")
|
||||
api.SetCookie("token", "M0p9VatZSeSHfrosD5IViAVl73IcA8mlcuHIV5sG6Zpv83a7JE0wY3t26aEhrrs_MR5gtLSFF1UIkt8HAjaXow")
|
||||
}
|
||||
|
||||
func handleError(t *testing.T, err error) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
@@ -45,10 +44,12 @@ const (
|
||||
ErrCodeSysErr = 700 // 系统错误,按美团外卖技术支持的说法,可当成需重试的错误
|
||||
ErrCodeAccessLimited = 711 // 接口调用过于频繁,触发流控,请降低调用频率
|
||||
|
||||
ErrCodeNoAppFood = 805 // 不存在此菜品
|
||||
ErrCodeNoSuchOrder = 808 // 不存在此订单
|
||||
ErrCodeSkuCategoryNotExist = 1021 // 菜品分类不存在
|
||||
ErrCodeSkuCategoryExist = 1037 // 菜品分类已存在
|
||||
ErrCodeNoAppFood = 805 // 不存在此菜品
|
||||
ErrCodeNoSuchOrder = 806 // 不存在此订单
|
||||
ErrCodeOpFailed = 808 // 操作失败(如订单在操作时,状态已变更等情况)
|
||||
ErrCodeSkuCategoryNotExist = 1021 // 菜品分类不存在
|
||||
ErrCodeSkuCategoryExist = 1037 // 菜品分类已存在
|
||||
ErrCodeCanNotModifyStoreDeliveryInfo = 3018 // 商家已接入美团配送,不可修改门店配送相关信息
|
||||
)
|
||||
|
||||
type API struct {
|
||||
@@ -59,16 +60,15 @@ type API struct {
|
||||
callbackURL string
|
||||
client *http.Client
|
||||
config *platformapi.APIConfig
|
||||
|
||||
locker sync.RWMutex
|
||||
userCookies map[string]string
|
||||
}
|
||||
|
||||
var (
|
||||
canRetryCodes = map[int]int{
|
||||
ErrCodeSysErr: 1,
|
||||
ErrCodeAccessLimited: 1,
|
||||
}
|
||||
canRecoverCodes = map[int]int{
|
||||
ErrCodeSysErr: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func New(appID, secret, callbackURL string, config ...*platformapi.APIConfig) *API {
|
||||
@@ -82,8 +82,6 @@ func New(appID, secret, callbackURL string, config ...*platformapi.APIConfig) *A
|
||||
callbackURL: callbackURL,
|
||||
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||
config: &curConfig,
|
||||
|
||||
userCookies: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +143,7 @@ func (a *API) AccessAPI2(cmd string, isGet bool, bizParams map[string]interface{
|
||||
fw.Write(imgData.([]byte))
|
||||
}
|
||||
for k, v := range params {
|
||||
fmt.Println(k, " ", v)
|
||||
// baseapi.SugarLogger.Debug(k, " ", v)
|
||||
w.WriteField(k, url.QueryEscape(fmt.Sprint(v)))
|
||||
}
|
||||
w.Close()
|
||||
@@ -173,6 +171,8 @@ func (a *API) AccessAPI2(cmd string, isGet bool, bizParams map[string]interface{
|
||||
newErr := utils.NewErrorIntCode(errorInfo["msg"].(string), int(utils.MustInterface2Int64(errorInfo["code"])))
|
||||
if canRetryCodes[newErr.IntCode()] == 1 {
|
||||
return platformapi.ErrLevelExceedLimit, newErr
|
||||
} else if canRecoverCodes[newErr.IntCode()] == 1 {
|
||||
return platformapi.ErrLevelRecoverableErr, newErr
|
||||
}
|
||||
return platformapi.ErrLevelCodeIsNotOK, newErr
|
||||
}
|
||||
|
||||
@@ -67,6 +67,11 @@ const (
|
||||
NotifyTypeCancelRefundComplaint = "cancelRefundComplaint" // 用户取消退款申诉
|
||||
)
|
||||
|
||||
const (
|
||||
OrderPickTypeNormal = 0 // 普通(配送)
|
||||
OrderPickTypeSelf = 1 // 用户到店自取
|
||||
)
|
||||
|
||||
const (
|
||||
UserApplyCancelWaitMinute = 30 // 用户申请退款后,商家未在30分钟内(大连锁商家为3小时内)处理退款请求,系统将自动同意退款
|
||||
)
|
||||
@@ -308,6 +313,23 @@ type GetOrderIdByDaySeqResult struct {
|
||||
OrderIDs []int64 `json:"order_ids"`
|
||||
}
|
||||
|
||||
type UserRealPhoneNumberInfo struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
AppPoiCode string `json:"app_poi_code"`
|
||||
WmOrderIDView string `json:"wm_order_id_view"`
|
||||
DaySeq int `json:"day_seq"`
|
||||
RealPhoneNumber string `json:"real_phone_number"` // 订单收货人的真实手机号码
|
||||
RealOrderPhoneNumber string `json:"real_order_phone_number"` // 鲜花绿植类订单预订人的真实手机号码,如无则返回空。
|
||||
}
|
||||
|
||||
type RiderRealPhoneNumberInfo struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
AppPoiCode string `json:"app_poi_code"`
|
||||
WmOrderIDView string `json:"wm_order_id_view"`
|
||||
RiderName string `json:"rider_name"`
|
||||
RiderRealPhoneNumber string `json:"rider_real_phone_number"` // 骑手真实手机号
|
||||
}
|
||||
|
||||
func (a *API) OrderReceived(orderID int64) (err error) {
|
||||
_, err = a.AccessAPI("order/poi_received", true, map[string]interface{}{
|
||||
KeyOrderID: orderID,
|
||||
@@ -462,8 +484,10 @@ func (a *API) OrderLogisticsStatus(orderID int64) (status map[string]interface{}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 拉取用户真实手机号(必接)
|
||||
// https://developer.waimai.meituan.com/home/docDetail/222
|
||||
// limit最大为MaxBatchPullPhoneNumberLimit = 1000
|
||||
func (a *API) OrderBatchPullPhoneNumber(poiCode string, offset, limit int) (realNumberList []map[string]interface{}, err error) {
|
||||
func (a *API) OrderBatchPullPhoneNumber(poiCode string, offset, limit int) (realNumberList []*UserRealPhoneNumberInfo, err error) {
|
||||
params := map[string]interface{}{
|
||||
"offset": offset,
|
||||
"limit": limit,
|
||||
@@ -473,9 +497,27 @@ func (a *API) OrderBatchPullPhoneNumber(poiCode string, offset, limit int) (real
|
||||
}
|
||||
result, err := a.AccessAPI("order/batchPullPhoneNumber", false, params)
|
||||
if err == nil {
|
||||
return utils.Slice2MapSlice(result.([]interface{})), nil
|
||||
err = utils.Map2StructByJson(result, &realNumberList, false)
|
||||
}
|
||||
return nil, err
|
||||
return realNumberList, err
|
||||
}
|
||||
|
||||
// 拉取骑手真实手机号(必接),美团2019-09-17才开始灰度上线
|
||||
// https://developer.waimai.meituan.com/home/docDetail/388
|
||||
// limit最大为MaxBatchPullPhoneNumberLimit = 1000
|
||||
func (a *API) OrderGetRiderInfoPhoneNumber(poiCode string, offset, limit int) (realNumberList []*RiderRealPhoneNumberInfo, err error) {
|
||||
params := map[string]interface{}{
|
||||
"offset": offset,
|
||||
"limit": limit,
|
||||
}
|
||||
if poiCode != "" {
|
||||
params[KeyAppPoiCode] = poiCode
|
||||
}
|
||||
result, err := a.AccessAPI("order/getRiderInfoPhoneNumber", false, params)
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(result, &realNumberList, false)
|
||||
}
|
||||
return realNumberList, err
|
||||
}
|
||||
|
||||
// 专快混配送转为商家自配送
|
||||
|
||||
@@ -80,14 +80,19 @@ func TestOrderLogisticsStatus(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOrderBatchPullPhoneNumber(t *testing.T) {
|
||||
result, err := api.OrderBatchPullPhoneNumber(testPoiCode, 0, 10)
|
||||
result, err := api.OrderBatchPullPhoneNumber(testPoiCode, 0, MaxBatchPullPhoneNumberLimit)
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(result) == 0 {
|
||||
t.Fatal("result should have value")
|
||||
}
|
||||
|
||||
func TestOrderGetRiderInfoPhoneNumber(t *testing.T) {
|
||||
result, err := api.OrderGetRiderInfoPhoneNumber(testPoiCode, 0, MaxBatchPullPhoneNumberLimit)
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
func TestGetOrderRefundDetail(t *testing.T) {
|
||||
|
||||
@@ -47,6 +47,9 @@ type PoiInfo struct {
|
||||
Utime int64 `json:"utime,omitempt"`
|
||||
}
|
||||
|
||||
// todo 此函数在open_level与is_online开店,由于一些原因并没有成功时,好像并不会报错
|
||||
// 经常会奇怪的报错:商家已接入美团配送,不可修改门店配送相关信息,但实际并没有修改任何与配送相关的东西
|
||||
// 参见:https://developer.waimai.meituan.com/home/myquestionDetail/6194
|
||||
func (a *API) PoiSave(poiCode string, poiParams map[string]interface{}) (err error) {
|
||||
_, err = a.AccessAPI("poi/save", false, utils.MergeMaps(utils.Params2Map(KeyAppPoiCode, poiCode), poiParams))
|
||||
return err
|
||||
@@ -150,6 +153,8 @@ func (a *API) PoiShipTimeUpdate(poiCode, shippingTime string) (err error) {
|
||||
}
|
||||
|
||||
// 美团要求必须是jpg|jpeg图片格式,且imgName必须以jpg或jpeg结尾
|
||||
// 此接口虽然要求poiCode参数,但经过测试,发现上传的图片可以跨门店使用
|
||||
// imgName好像不支持中文,否则会报签名错
|
||||
func (a *API) ImageUpload(poiCode, imgName string, imgData []byte) (imgID string, err error) {
|
||||
result, err := a.AccessAPI("image/upload", false, map[string]interface{}{
|
||||
KeyAppPoiCode: poiCode,
|
||||
|
||||
@@ -22,7 +22,8 @@ func TestPoiGetIDs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPoiMGet(t *testing.T) {
|
||||
result, err := api.PoiMGet([]string{testPoiCode})
|
||||
result, err := api.PoiMGet([]string{"2461723"})
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -32,7 +33,6 @@ func TestPoiMGet(t *testing.T) {
|
||||
if result[0].AppPoiCode != testPoiCode {
|
||||
t.Fatal("test_poi_01 is not equal")
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
func TestPoiSave(t *testing.T) {
|
||||
@@ -80,3 +80,21 @@ func TestPoiStatus(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPoiShipTimeUpdate(t *testing.T) {
|
||||
err := api.PoiShipTimeUpdate("7174130", "00:00-23:00")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = api.PoiOpen("6741258")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPoiOpen(t *testing.T) {
|
||||
err := api.PoiOpen("6735933")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ type AppFoodResult struct {
|
||||
// 创建二级分类,secondaryName为二级分类名,
|
||||
// (如果originName为空,同时创建一级分类,所以如果只是创建二级分类,originName与name要填一样的,此时sequence指的二级分类的sequence,一级分类的sequence为缺省值)
|
||||
// 修改二级分类,originName为二级分类名,name为二级分类新名,secondaryName为空
|
||||
// https://developer.waimai.meituan.com/home/questionDetail/4669
|
||||
func (a *API) RetailCatUpdate(poiCode, originName, name, secondaryName string, sequence int) (err error) {
|
||||
params := map[string]interface{}{
|
||||
KeyAppPoiCode: poiCode,
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -17,18 +18,18 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DefClientTimeout = 15 * time.Second
|
||||
DefSleepSecondWhenExceedLimit = 3 * time.Second
|
||||
DefMaxRecoverableRetryCount = 1
|
||||
DefMaxExceedLimitRetryCount = 25
|
||||
DefClientTimeout = 30 * time.Second
|
||||
DefMaxSleepSecondWhenExceedLimit = 62 // 超频类错误最大重试间隙(秒)
|
||||
DefMaxExceedLimitRetryCount = 25 // 超频类错误最大重试次数
|
||||
DefMaxRecoverableRetryCount = 1 // 可恢复类错误(一般指网络错),最大重试次数
|
||||
|
||||
KeyTrackInfo = "TrackInfo"
|
||||
)
|
||||
|
||||
type APIRetryConfig struct {
|
||||
MaxExceedLimitRetryCount int
|
||||
MaxRecoverableRetryCount int
|
||||
SleepSecondWhenExceedLimit time.Duration
|
||||
MaxExceedLimitRetryCount int
|
||||
MaxRecoverableRetryCount int
|
||||
MaxSleepSecondWhenExceedLimit int
|
||||
}
|
||||
|
||||
type APIConfig struct {
|
||||
@@ -45,9 +46,9 @@ type AccessPlatformAPIWithRetryParam struct {
|
||||
var (
|
||||
DefAPIConfig = APIConfig{
|
||||
APIRetryConfig: APIRetryConfig{
|
||||
MaxExceedLimitRetryCount: DefMaxExceedLimitRetryCount,
|
||||
MaxRecoverableRetryCount: DefMaxRecoverableRetryCount,
|
||||
SleepSecondWhenExceedLimit: DefSleepSecondWhenExceedLimit,
|
||||
MaxExceedLimitRetryCount: DefMaxExceedLimitRetryCount,
|
||||
MaxRecoverableRetryCount: DefMaxRecoverableRetryCount,
|
||||
MaxSleepSecondWhenExceedLimit: DefMaxSleepSecondWhenExceedLimit,
|
||||
},
|
||||
ClientTimeout: DefClientTimeout,
|
||||
}
|
||||
@@ -90,6 +91,11 @@ func getClonedData(requestURL *url.URL, r *bytes.Buffer) string {
|
||||
return retVal
|
||||
}
|
||||
|
||||
func NewDefAPIConfig() (conf *APIConfig) {
|
||||
obj := DefAPIConfig
|
||||
return &obj
|
||||
}
|
||||
|
||||
func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.Request, config *APIConfig, handleResponse func(response *http.Response, bodyStr string, bodyMap map[string]interface{}) (string, error)) error {
|
||||
exceedLimitRetryCount := 0
|
||||
recoverableErrorRetryCount := 0
|
||||
@@ -101,12 +107,10 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
|
||||
}
|
||||
beginTime := time.Now()
|
||||
trackInfo := request.Header.Get(KeyTrackInfo)
|
||||
if trackInfo == "" {
|
||||
trackInfo = utils.GetUUID()
|
||||
// request.Header.Set(KeyTrackInfo, trackID)
|
||||
} else {
|
||||
if trackInfo != "" {
|
||||
request.Header.Del(KeyTrackInfo)
|
||||
}
|
||||
trackInfo += ", " + utils.GetUUID()
|
||||
baseapi.SugarLogger.Debugf("begin AccessPlatformAPIWithRetry:%s do:%s url:%v", trackInfo, request.Method, request.URL)
|
||||
response, err := client.Do(request)
|
||||
baseapi.SugarLogger.Debugf("end AccessPlatformAPIWithRetry:%s do url:%v, request:%s", trackInfo, request.URL, getClonedData(request.URL, savedBuf))
|
||||
@@ -174,7 +178,11 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
|
||||
} else if errLevel == ErrLevelExceedLimit {
|
||||
exceedLimitRetryCount++
|
||||
if exceedLimitRetryCount <= config.MaxExceedLimitRetryCount {
|
||||
time.Sleep(config.SleepSecondWhenExceedLimit)
|
||||
sleepSeconds := int(math.Exp2(float64(exceedLimitRetryCount)))
|
||||
if sleepSeconds > config.MaxSleepSecondWhenExceedLimit {
|
||||
sleepSeconds = config.MaxSleepSecondWhenExceedLimit
|
||||
}
|
||||
time.Sleep(time.Duration(sleepSeconds) * time.Second)
|
||||
continue
|
||||
}
|
||||
} else if errLevel == ErrLevelRecoverableErr {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
type APICookie struct {
|
||||
locker sync.RWMutex
|
||||
sync.RWMutex
|
||||
storeCookies map[string]string
|
||||
}
|
||||
|
||||
@@ -44,28 +44,28 @@ func (a *APICookie) SetCookieWithStr(cookieStr string) {
|
||||
}
|
||||
|
||||
func (a *APICookie) SetCookie(key, value string) {
|
||||
a.locker.Lock()
|
||||
defer a.locker.Unlock()
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
a.createMapIfNeeded()
|
||||
a.storeCookies[key] = value
|
||||
}
|
||||
|
||||
func (a *APICookie) GetCookie(key string) string {
|
||||
a.locker.RLock()
|
||||
defer a.locker.RUnlock()
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
a.createMapIfNeeded()
|
||||
return a.storeCookies[key]
|
||||
}
|
||||
|
||||
func (a *APICookie) GetCookieCount() int {
|
||||
a.locker.RLock()
|
||||
defer a.locker.RUnlock()
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
return len(a.storeCookies)
|
||||
}
|
||||
|
||||
func (a *APICookie) FillRequestCookies(r *http.Request) *http.Request {
|
||||
a.locker.RLock()
|
||||
defer a.locker.RUnlock()
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
for k, v := range a.storeCookies {
|
||||
r.AddCookie(&http.Cookie{
|
||||
Name: k,
|
||||
|
||||
@@ -56,6 +56,15 @@ type TokenInfo struct {
|
||||
MachineCode string `json:"machine_code"`
|
||||
}
|
||||
|
||||
type PrinterOrderResult struct {
|
||||
Content string `json:"content"`
|
||||
ID string `json:"id"`
|
||||
OriginID string `json:"origin_id"`
|
||||
PrintTime string `json:"print_time"`
|
||||
ReceivingTime string `json:"receiving_time"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func New(clientID, clientSecret string, config ...*platformapi.APIConfig) *API {
|
||||
curConfig := platformapi.DefAPIConfig
|
||||
if len(config) > 0 {
|
||||
@@ -238,7 +247,6 @@ func (a *API) GetPrinterToken(machineCode, qrKey string) (tokenInfo *TokenInfo,
|
||||
}, "")
|
||||
if err == nil {
|
||||
err = utils.Map2StructByJson(result, &tokenInfo, false)
|
||||
a.SetToken(tokenInfo.AccessToken)
|
||||
}
|
||||
return tokenInfo, err
|
||||
}
|
||||
@@ -257,3 +265,16 @@ func (a *API) CancelAll(machineCode, token string) (err error) {
|
||||
func (a *API) PlayText(machineCode, orderID, text, token string) (err error) {
|
||||
return a.printMsg(machineCode, orderID, fmt.Sprintf("<audio>%s,9,0</audio>", strings.Replace(text, ",", ".", -1)), token)
|
||||
}
|
||||
|
||||
// pageIndex从1开始,pageSize最大为100
|
||||
func (a *API) GetOrderPagingList(machineCode, token string, pageIndex, pageSize int) (orderResultList []*PrinterOrderResult, err error) {
|
||||
result, err := a.AccessAPI("printer/getorderpaginglist", map[string]interface{}{
|
||||
"machine_code": machineCode,
|
||||
"page_index": pageIndex,
|
||||
"page_size": pageSize,
|
||||
}, token)
|
||||
if err != nil {
|
||||
err = utils.Map2StructByJson(result, &orderResultList, false)
|
||||
}
|
||||
return orderResultList, err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func init() {
|
||||
|
||||
// 自有应用
|
||||
api = New("1039586024", "4885d07c2997b661102e4b6099c0bf3b")
|
||||
api.SetToken("7884617f9eeb4c28933569f94a95b5c3")
|
||||
api.SetToken("3a38e3cec7974b459a6f0a381c9b0312")
|
||||
|
||||
// 开放应用
|
||||
// api = New("1098307169", "d5eedb40c99e6691b1ca2ba82a363d6a")
|
||||
@@ -42,19 +42,19 @@ func TestRetrieveToken(t *testing.T) {
|
||||
|
||||
func TestAddPrinter(t *testing.T) {
|
||||
// err := api.AddPrinter("4004600675", "fem2ukwvduik", "公司测试打印机1")
|
||||
// 4004617180 公司测试打印机2
|
||||
err := api.AddPrinter("4004600675", "fem2ukwvduik", "测试打印机1")
|
||||
// 4004617180, 381870509796 公司测试打印机2
|
||||
err := api.AddPrinter("4004615546", "7nxsw668yqtk", "测试打印机1")
|
||||
handleError(t, err)
|
||||
}
|
||||
|
||||
func TestDeletePrinter(t *testing.T) {
|
||||
err := api.DeletePrinter("4004611945")
|
||||
err := api.DeletePrinter("4004615546")
|
||||
handleError(t, err)
|
||||
}
|
||||
|
||||
func TestPrintMsg(t *testing.T) {
|
||||
// 4004606481
|
||||
err := api.PrintMsg("4004600675", utils.GetUUID(), "<FS2>饿百取货码</FS2>")
|
||||
err := api.PrintMsg("4004615546", utils.GetUUID(), "<FS2>饿百取货码</FS2>")
|
||||
handleError(t, err)
|
||||
}
|
||||
|
||||
@@ -65,13 +65,13 @@ func TestPrintMsgWithToken(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetPrintStatus(t *testing.T) {
|
||||
state, err := api.GetPrintStatus("4004617180")
|
||||
state, err := api.GetPrintStatus("4004615546")
|
||||
handleError(t, err)
|
||||
baseapi.SugarLogger.Debug(state)
|
||||
}
|
||||
|
||||
func TestGetPrintStatusWithToken(t *testing.T) {
|
||||
state, err := api.GetPrintStatusWithToken("4004600675", "b1a36aa8de5647d2b08af49db11a9c9d")
|
||||
state, err := api.GetPrintStatusWithToken("4004617242", "88de89a384714436a5d1ca23e8991e15")
|
||||
handleError(t, err)
|
||||
baseapi.SugarLogger.Debug(state)
|
||||
}
|
||||
@@ -91,3 +91,15 @@ func TestPlayText(t *testing.T) {
|
||||
err := api.PlayText("4004617180", utils.GetUUID(), "我们已安排%s配送员%s负责配送。^_^", "")
|
||||
handleError(t, err)
|
||||
}
|
||||
|
||||
func TestRefreshToken(t *testing.T) {
|
||||
tokenInfo, err := api.RefreshToken("c565a8983887488eb2a708ca118ce43c")
|
||||
handleError(t, err)
|
||||
t.Log(utils.Format4Output(tokenInfo, true))
|
||||
}
|
||||
|
||||
func TestGetOrderPagingList(t *testing.T) {
|
||||
result, err := api.GetOrderPagingList("4004613792", "", 1, 50)
|
||||
handleError(t, err)
|
||||
t.Log(utils.Format4Output(result, true))
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"github.com/fatih/structs"
|
||||
"github.com/gazeboxu/structs"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
@@ -70,15 +71,22 @@ func TryInterface2Int64(data interface{}) (num int64, err error) {
|
||||
if dataNumber, ok := data.(int); ok {
|
||||
return int64(dataNumber), nil
|
||||
}
|
||||
dataNumber, ok := data.(json.Number)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("data is not json.Number:%v to int64", data)
|
||||
if dataNumber, ok := data.(int32); ok {
|
||||
return int64(dataNumber), nil
|
||||
}
|
||||
retVal, err := dataNumber.Int64()
|
||||
if err != nil {
|
||||
return num, err
|
||||
if dataNumber, ok := data.(int16); ok {
|
||||
return int64(dataNumber), nil
|
||||
}
|
||||
return retVal, nil
|
||||
if dataNumber, ok := data.(int8); ok {
|
||||
return int64(dataNumber), nil
|
||||
}
|
||||
if dataNumber, ok := data.(json.Number); ok {
|
||||
return dataNumber.Int64()
|
||||
}
|
||||
if str, ok := data.(string); ok {
|
||||
return Str2Int64WithDefault(str, 0), nil
|
||||
}
|
||||
return 0, fmt.Errorf("data is not json.Number, it's %s, value:%v", reflect.TypeOf(data).String(), data)
|
||||
}
|
||||
|
||||
func MustInterface2Int64(data interface{}) int64 {
|
||||
@@ -114,15 +122,13 @@ func TryInterface2Float64(data interface{}) (num float64, err error) {
|
||||
if dataNumber, ok := data.(float32); ok {
|
||||
return float64(dataNumber), nil
|
||||
}
|
||||
dataNumber, ok := data.(json.Number)
|
||||
if !ok {
|
||||
return num, fmt.Errorf("data is not json.Number:%v", data)
|
||||
if dataNumber, ok := data.(json.Number); ok {
|
||||
return dataNumber.Float64()
|
||||
}
|
||||
retVal, err := dataNumber.Float64()
|
||||
if err != nil {
|
||||
return num, err
|
||||
if str, ok := data.(string); ok {
|
||||
return Str2Float64WithDefault(str, 0), nil
|
||||
}
|
||||
return retVal, nil
|
||||
return 0, fmt.Errorf("data is not json.Number, it's %s, value:%v", reflect.TypeOf(data).String(), data)
|
||||
}
|
||||
|
||||
func MustInterface2Float64(data interface{}) float64 {
|
||||
@@ -329,6 +335,10 @@ func IsTimeZero(timeValue time.Time) bool {
|
||||
return timeValue == DefaultTimeValue || timeValue == ZeroTimeValue
|
||||
}
|
||||
|
||||
func IsPtrTimeZero(timePtr *time.Time) bool {
|
||||
return timePtr == nil || *timePtr == DefaultTimeValue || *timePtr == ZeroTimeValue
|
||||
}
|
||||
|
||||
func HTTPBody2Values(data []byte, needDecode bool) (url.Values, error) {
|
||||
bodyStr := string(data)
|
||||
if needDecode {
|
||||
@@ -443,36 +453,22 @@ func MergeMaps(firstMap map[string]interface{}, otherMaps ...map[string]interfac
|
||||
return retVal
|
||||
}
|
||||
|
||||
func Struct2MapByJson(obj interface{}) (mapData map[string]interface{}) {
|
||||
func Struct2Map(obj interface{}, tagName string, isFlattenAnonymous bool) (mapData map[string]interface{}) {
|
||||
if tagName == "" {
|
||||
tagName = "json"
|
||||
}
|
||||
structsObj := structs.New(obj)
|
||||
structsObj.TagName = "json"
|
||||
structsObj.TagName = tagName
|
||||
structsObj.IsFlattenAnonymous = true
|
||||
return structsObj.Map()
|
||||
}
|
||||
|
||||
// 此函数将MAP中所有的子MAP中的数据提升到最上层,相同字段会覆盖父MAP的
|
||||
func FlatMap(in map[string]interface{}) map[string]interface{} {
|
||||
keys := []string{}
|
||||
maps := []map[string]interface{}{}
|
||||
for k, v := range in {
|
||||
if vMap, ok := v.(map[string]interface{}); ok {
|
||||
vMap = FlatMap(vMap)
|
||||
maps = append(maps, vMap)
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
if len(maps) > 0 {
|
||||
retVal := MergeMaps(in, maps...)
|
||||
for _, v := range keys {
|
||||
delete(retVal, v)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
return in
|
||||
func Struct2MapByJson(obj interface{}) (mapData map[string]interface{}) {
|
||||
return Struct2Map(obj, "", false)
|
||||
}
|
||||
|
||||
func Struct2FlatMap(obj interface{}) map[string]interface{} {
|
||||
m := Struct2MapByJson(obj)
|
||||
return FlatMap(m)
|
||||
return Struct2Map(obj, "", true)
|
||||
}
|
||||
|
||||
// !!! 此函数好像不支持struct是内嵌结构的
|
||||
|
||||
@@ -84,3 +84,40 @@ func TestTime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStruct2MapByJson(t *testing.T) {
|
||||
type InnerKK struct {
|
||||
IntData int
|
||||
StrData string
|
||||
ObjData time.Time
|
||||
}
|
||||
type KK struct {
|
||||
IntData int
|
||||
A int
|
||||
B string
|
||||
C time.Time
|
||||
InnerKK
|
||||
InnerKK2 InnerKK
|
||||
}
|
||||
kk := &KK{
|
||||
InnerKK: InnerKK{
|
||||
IntData: 1,
|
||||
StrData: "hello",
|
||||
},
|
||||
}
|
||||
mapData := Struct2MapByJson(kk)
|
||||
t.Log(Format4Output(mapData, false))
|
||||
// t.Log(mapData)
|
||||
// t.Log(kk)
|
||||
}
|
||||
|
||||
// func TestStruct2MapByJson(t *testing.T) {
|
||||
// mapData := Struct2MapByJson(&struct {
|
||||
// IntData int `structs:"dataInt"`
|
||||
// StrData string `json:"-"`
|
||||
// }{
|
||||
// IntData: 1,
|
||||
// StrData: "2",
|
||||
// })
|
||||
// t.Log(mapData)
|
||||
// }
|
||||
|
||||
@@ -175,17 +175,6 @@ func TestTrimBlanChar(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStruct2MapByJson(t *testing.T) {
|
||||
mapData := Struct2MapByJson(&struct {
|
||||
IntData int `structs:"dataInt"`
|
||||
StrData string `json:"-"`
|
||||
}{
|
||||
IntData: 1,
|
||||
StrData: "2",
|
||||
})
|
||||
t.Log(mapData)
|
||||
}
|
||||
|
||||
func TestLimitUTF8StringLen(t *testing.T) {
|
||||
for _, v := range [][]interface{}{
|
||||
[]interface{}{
|
||||
|
||||
69
utils/utils_type.go
Normal file
69
utils/utils_type.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package utils
|
||||
|
||||
import "time"
|
||||
|
||||
func String2Pointer(value string) *string {
|
||||
return &value
|
||||
}
|
||||
|
||||
func Pointer2String(ptr *string) (value string) {
|
||||
if ptr != nil {
|
||||
value = *ptr
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func Int2Pointer(value int) *int {
|
||||
return &value
|
||||
}
|
||||
|
||||
func Pointer2Int(ptr *int) (value int) {
|
||||
if ptr != nil {
|
||||
value = *ptr
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func Int64ToPointer(value int64) *int64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
func Pointer2Int64(ptr *int64) (value int64) {
|
||||
if ptr != nil {
|
||||
value = *ptr
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func Float32ToPointer(value float32) *float32 {
|
||||
return &value
|
||||
}
|
||||
|
||||
func Pointer2Float32(ptr *float32) (value float32) {
|
||||
if ptr != nil {
|
||||
value = *ptr
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func Float64ToPointer(value float64) *float64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
func Pointer2Float64(ptr *float64) (value float64) {
|
||||
if ptr != nil {
|
||||
value = *ptr
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func Time2Pointer(value time.Time) *time.Time {
|
||||
return &value
|
||||
}
|
||||
|
||||
func Pointer2Time(ptr *time.Time) (value time.Time) {
|
||||
if ptr != nil {
|
||||
value = *ptr
|
||||
}
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user