Files
baseapi/platformapi/jdapi/store_page.go

469 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package jdapi
import (
"bytes"
"crypto/md5"
"fmt"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"regexp"
"strings"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
const (
getStoreURL = "https://daojia.jd.com"
accessStorePageCookieName = "shop.o2o.jd.com1"
accessStorePageCookieName2 = "lsp-store1.jddj.com"
)
type SkuPageImg struct {
Big string `json:"big"`
Share string `json:"share"`
Small string `json:"small"`
}
type CorporationInfo struct {
Scope string `json:"scope"`
OperName string `json:"oper_name"`
Status string `json:"status"`
BelongOrg string `json:"belong_org"`
CreditNo string `json:"credit_no"`
RegNo string `json:"reg_no"`
ID string `json:"id"`
OrgNo string `json:"org_no"`
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 {
IdentifyType string `json:"identify_type"`
ShouldCapiItems []interface{} `json:"should_capi_items"`
StockType string `json:"stock_type"`
IdentifyNo string `json:"identify_no"`
RealCapiItems []interface{} `json:"real_capi_items"`
Name string `json:"name"`
} `json:"partners"`
Name string `json:"name"`
Province string `json:"province"`
TermStart string `json:"term_start"`
AbnormalItems []interface{} `json:"abnormal_items"`
CheckDate string `json:"check_date"`
RegistCapi string `json:"regist_capi"`
StartDate string `json:"start_date"`
Changerecords []struct {
BeforeContent string `json:"before_content"`
ChangeDate string `json:"change_date"`
ChangeItem string `json:"change_item"`
AfterContent string `json:"after_content"`
} `json:"changerecords"`
Branches []interface{} `json:"branches"`
Employees []struct {
JobTitle string `json:"job_title"`
Name string `json:"name"`
} `json:"employees"`
}
type PageShopInfo struct {
DisCatName string `json:"disCatName"`
DisplayType string `json:"displayType"`
FreightWords string `json:"freightWords"`
IsCart bool `json:"isCart"`
IsJb int `json:"isJb"`
IsWithHome bool `json:"isWithHome"`
LogoURL string `json:"logoUrl"`
StoreActPageList []interface{} `json:"storeActPageList"`
StoreCommentVO struct {
BuyerShowName string `json:"buyerShowName"`
CreateTime string `json:"createTime"`
IsOrgComment int `json:"isOrgComment"`
OrgCommentContent string `json:"orgCommentContent"`
Score4 int `json:"score4"`
Score4Content string `json:"score4Content"`
ScoreAvg float64 `json:"scoreAvg"`
ShowTotalCount bool `json:"showTotalCount"`
Skus []interface{} `json:"skus"`
StoreStar float64 `json:"storeStar"`
TagInfoItemList []string `json:"tagInfoItemList"`
TotalCount int `json:"totalCount"`
} `json:"storeCommentVO"`
StoreDesc string `json:"storeDesc"`
StoreInfo struct {
BackgroundType string `json:"backgroundType"`
CarrierNo int `json:"carrierNo"`
CloseStatus int `json:"closeStatus"`
DeliveryFirst string `json:"deliveryFirst"`
DeliverySecond string `json:"deliverySecond"`
ExpectArrivedTips []struct {
Msg string `json:"msg"`
Type int `json:"type"`
} `json:"expectArrivedTips"`
Flag bool `json:"flag"`
FollowNo string `json:"followNo"`
FreightTag struct {
BelongIndustry int `json:"belongIndustry"`
Type int `json:"type"`
Words string `json:"words"`
} `json:"freightTag"`
FreightWords string `json:"freightWords"`
InSaleNum string `json:"inSaleNum"`
Industry string `json:"industry"`
IsFollow bool `json:"isFollow"`
IsMembership bool `json:"isMembership"`
IsOverZone bool `json:"isOverZone"`
IsTimeFight int `json:"isTimeFight"`
LogoURL string `json:"logoUrl"`
MonthSaleNum string `json:"monthSaleNum"`
OrgCode string `json:"orgCode"`
Params string `json:"params"`
SearchLinkageFlag bool `json:"searchLinkageFlag"`
ServiceTimes []struct {
EndTime string `json:"endTime"`
StartTime string `json:"startTime"`
} `json:"serviceTimes"`
ShowType string `json:"showType"`
StationStatus int `json:"stationStatus"`
StoreAddress string `json:"storeAddress"`
StoreCertificateURL string `json:"storeCertificateUrl"`
StoreID string `json:"storeId"`
StoreName string `json:"storeName"`
StoreTel string `json:"storeTel"`
To string `json:"to"`
UpToSendprice int `json:"upToSendprice"`
} `json:"storeInfo"`
StoreShareURL string `json:"storeShareUrl"`
}
const (
QualifyTypeCompany = "25" // 营业执照
QualifyTypePerson = "22" // 身份证,个体工商户要求填
QualifyTypeAddInfo = "31" // 附加信息,如果身份证是长期有效,要求身份证背面信息
SaveQualifyActionTypeCommit = 0 // 提交
SaveQualifyActionTypeSave = 1 // 暂时保存
)
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
if !isPost {
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 {
fmt.Println(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")
}
if err != nil {
return nil
}
a.FillRequestCookies(request)
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")
}
retVal = jsonResult1
code, ok := jsonResult1["code"].(string)
if !ok {
return platformapi.ErrLevelGeneralFail, utils.NewErrorCode(utils.Format4Output(jsonResult1, true), "999")
}
if code == ResponseCodeSuccess {
if resultKey != "" {
retVal = jsonResult1[resultKey]
}
return platformapi.ErrLevelSuccess, nil
}
newErr := utils.NewErrorCode(jsonResult1["msg"].(string), code)
if _, ok := pageExceedLimitCodes[code]; ok {
return platformapi.ErrLevelExceedLimit, newErr
} else if _, ok := pageCanRetryCodes[code]; ok {
return platformapi.ErrLevelRecoverableErr, newErr
} else {
baseapi.SugarLogger.Debugf("jd AccessStorePage failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
return platformapi.ErrLevelCodeIsNotOK, newErr
}
})
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 {
return retVal["mobile"].(string), nil
}
return "", err
}
func (a *API) GetStoreOrderInfo(orderId, stationNo string) (storeOrderInfo map[string]interface{}, err error) {
params := map[string]interface{}{
"pageNo": 1,
"pageSize": 1,
"desc": true,
"param": orderId,
}
if stationNo != "" {
params["stationNo"] = stationNo
}
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{})
resultList := newOrderinfoMains["resultList"].([]interface{})
if len(resultList) > 0 {
return resultList[0].(map[string]interface{}), nil
}
return nil, fmt.Errorf("不能找到订单:%s的相关信息", orderId)
}
return nil, err
}
func (a *API) GetStoreOrderInfoList(fromTime, toTime string) (storeOrderList []map[string]interface{}, err error) {
pageSize := 100
pageNo := 1
params := map[string]interface{}{
"o2oOrderType": 10000,
"pageSize": pageSize,
"desc": true,
"startTimeQuery": fromTime,
"endTimeQuery": toTime,
// "stationNo": 0,
}
for {
params["pageNo"] = pageNo
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{})
resultList := newOrderinfoMains["resultList"].([]interface{})
storeOrderList = append(storeOrderList, utils.Slice2MapSlice(resultList)...)
if len(storeOrderList) >= int(utils.MustInterface2Int64(newOrderinfoMains["totalCount"])) {
return storeOrderList, nil
}
pageNo++
} else {
return nil, err
}
}
return nil, err
}
func (a *API) GetSkuPageInfo(skuId int64) (skuPageInfo map[string]interface{}, err error) {
skuIDMap := map[string]interface{}{
"skuId": utils.Int64ToStr(skuId),
"storeId": "0",
}
params := map[string]interface{}{
"platCode": "H5",
"functionId": "product/detailV6_0",
"appVersion": "6.7.0",
"body": utils.Format4Output(skuIDMap, true),
}
skuPageInfo, err = a.AccessStorePage("https://daojia.jd.com/client", params, 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)
}
return imgList, err
}
func (a *API) GetStoreInfo(storeId string) (storeInfo map[string]interface{}, err error) {
body := map[string]interface{}{
"storeId": storeId,
}
params := map[string]interface{}{
"appVersion": "6.1.0",
"functionId": "store/storeDetailV220",
"body": utils.Format4Output(body, true),
}
retVal, err := a.AccessStorePage("https://daojia.jd.com/client", params, false)
return retVal, err
}
func (a *API) GetStoreInfo2(storeID string) (storeInfo *PageShopInfo, err error) {
retVal, err := a.GetStoreInfo(storeID)
if err == nil {
err = utils.Map2StructByJson(retVal, &storeInfo, false)
}
return storeInfo, err
}
func signGetStoreList(bodyStr string) (signResult string) {
wb := "923047ae3f8d11d8b19aeb9f3d1bc200"
return fmt.Sprintf("%X", md5.Sum([]byte(bodyStr+wb)))
}
func (a *API) GetStoreList(lng string, lat string) (retVal map[string]interface{}, err error) {
body := map[string]interface{}{
"channelId": "3997",
"currentPage": 1,
"pageSize": 999,
"coordType": "2",
"platform": "1",
}
bodyStr := utils.Format4Output(body, true)
signResult := signGetStoreList(bodyStr)
params := map[string]interface{}{
"platCode": "H5",
"appVersion": "6.5.0",
"functionId": "zone/recommendStoreList",
"body": utils.Format4Output(body, true),
"signKey": signResult,
"lng": lng,
"lat": lat,
}
retVal, err = a.AccessStorePage("https://daojia.jd.com/client", params, false)
return retVal, err
}
func (a *API) GetCorporationInfo(stationNo, qualifyNumber string) (corporatonInfo *CorporationInfo, err error) {
result, err := a.AccessStorePage("https://sta-store.jddj.com/store/requestQualify.o2o", map[string]interface{}{
"stationNo": stationNo,
"qualifyNumber": qualifyNumber,
}, true)
if err == nil {
err = utils.Map2StructByJson(result, &corporatonInfo, false)
}
return corporatonInfo, err
}
func MonthSaleNum2Int(monthSaleNumStr string) (monthSaleNum int) {
searchResult := monthSaleNumReg.FindStringSubmatch(monthSaleNumStr)
if searchResult != nil && len(searchResult[1]) > 0 && len(searchResult[2]) > 0 {
monthSaleNum = int(utils.Str2Int64WithDefault(searchResult[1], 0))
if searchResult[2] == "千" {
monthSaleNum *= 1000
} else if searchResult[2] == "万" {
monthSaleNum *= 10000
}
} else {
monthSaleNum = int(utils.Str2Int64WithDefault(monthSaleNumStr, 0))
}
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
}