Files
jx-callback/business/partner/purchase/jd/store.go
2019-08-28 14:25:29 +08:00

461 lines
17 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 jd
import (
"fmt"
"strings"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
VendorStorePrefix = "京西菜市"
)
type tJdStoreInfo struct {
model.Store
JdCityCode int
JdDistrictCode int
JdStoreStatus int
VendorStoreID string `orm:"column(vendor_store_id)"`
RealLastOperator string
SyncStatus int
}
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorStoreID string) (*dao.StoreDetail, error) {
result, err := getAPI("").GetStoreInfoByStationNo(vendorStoreID)
if err == nil {
retVal := &dao.StoreDetail{
Store: model.Store{
Address: utils.Interface2String(result["stationAddress"]),
OpenTime1: JdOperationTime2JxOperationTime(result["serviceTimeStart1"]),
CloseTime1: JdOperationTime2JxOperationTime(result["serviceTimeEnd1"]),
OpenTime2: JdOperationTime2JxOperationTime(result["serviceTimeStart2"]),
CloseTime2: JdOperationTime2JxOperationTime(result["serviceTimeEnd2"]),
Status: JdStoreStatus2JxStatus(result["yn"], result["closeStatus"]),
Tel1: utils.Interface2String(result["phone"]),
},
}
retVal.OriginalName = utils.Interface2String(result["stationName"])
_, retVal.Name = jxutils.SplitStoreName(retVal.OriginalName, partner.StoreNameSeparator, VendorStorePrefix)
retVal.DeliveryType = JdDeliveryType2Jx(int(utils.MustInterface2Int64(result["carrierNo"])))
tel2 := utils.Interface2String(result["mobile"])
if tel2 != "" && tel2 != retVal.Tel1 {
retVal.Tel2 = tel2
}
lng := utils.MustInterface2Float64(result["lng"])
lat := utils.MustInterface2Float64(result["lat"])
retVal.Lng = jxutils.StandardCoordinate2Int(lng)
retVal.Lat = jxutils.StandardCoordinate2Int(lat)
db := dao.GetDB()
cityCode := int(utils.MustInterface2Int64(result["city"]))
if cityCode != 0 {
if city, err2 := dao.GetPlaceByJdCode(db, cityCode); err2 == nil {
retVal.CityCode = city.Code
districtName := utils.Interface2String(result["countyName"]) // 京东的市区号码与通用数据完全无法关联,只有通过名字来关联
if retVal.CityCode != 0 && districtName != "" {
if district, err2 := dao.GetPlaceByName(db, districtName, 3, city.Code); err2 == nil {
retVal.DistrictCode = district.Code
}
}
}
}
if retVal.DistrictCode == 0 {
retVal.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
if retVal.CityCode == 0 {
if district, err := dao.GetPlaceByCode(db, retVal.DistrictCode); err == nil {
retVal.CityCode = district.ParentCode
}
}
}
retVal.ID = int(utils.Str2Int64WithDefault(utils.Interface2String(result["outSystemId"]), 0))
result, err2 := getAPI("").GetDeliveryRangeByStationNo(vendorStoreID)
if err = err2; err == nil {
retVal.DeliveryRangeType = int8(utils.MustInterface2Int64(result["deliveryRangeType"]))
if retVal.DeliveryRangeType == model.DeliveryRangeTypePolygon {
retVal.DeliveryRange = strings.Trim(utils.Interface2String(result["deliveryRange"]), ";")
} else {
retVal.DeliveryRange = utils.Int64ToStr(utils.MustInterface2Int64(result["deliveryRangeRadius"]))
}
return retVal, nil
}
}
return nil, err
}
// stoerIDs为nil表示所有
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
var stores []*tJdStoreInfo
sql := `
SELECT t1.*, city.jd_code jd_city_code, district.jd_code jd_district_code, t2.status jd_store_status, t2.vendor_store_id,
IF(t1.updated_at > t2.updated_at, t1.last_operator, t2.last_operator) real_last_operator, t2.sync_status
FROM store t1
JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND (t2.deleted_at = ?)
LEFT JOIN place city ON t1.city_code = city.code
LEFT JOIN place district ON t1.district_code = district.code
WHERE t1.id = ?
ORDER BY t2.updated_at
`
if err = dao.GetRows(db, &stores, sql, model.VendorIDJD, utils.DefaultTimeValue, storeID); err == nil {
for _, store := range stores {
outSystemID := ""
if store.SyncStatus&model.SyncFlagDeletedMask == 0 {
outSystemID = utils.Int2Str(int(store.ID))
}
params := map[string]interface{}{
"outSystemId": outSystemID, // todo 直接修改这个字段可能会有问题
"phone": store.Tel1,
"mobile": store.Tel2,
}
fillOpTimeParams(params, store.GetOpTimeList())
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
params["stationName"] = jxutils.ComposeStoreName(store.Name, model.VendorIDJD)
}
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreAddress) != 0 {
params["stationAddress"] = store.Address
params["deliveryRangeType"] = store.DeliveryRangeType
params["coordinateType"] = 3 // 一直用高德
params["lng"] = jxutils.IntCoordinate2Standard(store.Lng)
params["lat"] = jxutils.IntCoordinate2Standard(store.Lat)
if store.JdCityCode != 0 {
params["city"] = store.JdCityCode
}
if store.JdDistrictCode != 0 {
params["county"] = store.JdDistrictCode
}
if store.DeliveryRangeType == model.DeliveryRangeTypePolygon {
params["coordinatePoints"] = store.DeliveryRange
} else {
params["deliveryRangeRadius"] = utils.Str2Int64WithDefault(store.DeliveryRange, 0)
}
}
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreStatus) != 0 {
_, params["closeStatus"] = JxStoreStatus2JdStatus(jxutils.MergeStoreStatus(store.Status, store.JdStoreStatus))
}
globals.SugarLogger.Debug(utils.Format4Output(params, false))
if globals.EnableJdStoreWrite {
if err = getAPI("").UpdateStoreInfo4Open(store.VendorStoreID, store.RealLastOperator, params); err != nil {
return err
}
}
}
}
return err
}
// 没用
// func (p *PurchaseHandler) DeleteStore(vendorStoreID, userName string) error {
// params := map[string]interface{}{
// "yn": 1,
// }
// return getAPI("").UpdateStoreInfo4Open(vendorStoreID, userName, params)
// }
// func (p *PurchaseHandler) EnableAutoAcceptOrder(vendorStoreID string, isEnabled bool) error {
// _, err := getAPI("").UpdateStoreConfig4Open(vendorStoreID, isEnabled)
// return err
// }
// func (p *PurchaseHandler) OpenStore(vendorStoreID string, userName string) error {
// params := map[string]interface{}{
// "closeStatus": 0,
// "storeNotice": "",
// }
// return getAPI("").UpdateStoreInfo4Open(vendorStoreID, userName, params)
// }
// func (p *PurchaseHandler) CloseStore(vendorStoreID, closeNotice, userName string) error {
// params := map[string]interface{}{
// "closeStatus": 1,
// "storeNotice": closeNotice,
// }
// return getAPI("").UpdateStoreInfo4Open(vendorStoreID, userName, params)
// }
///////////////////////
func (p *PurchaseHandler) GetAllStoresFromRemote() ([]*model.Store, error) {
ids, err := p.GetAllStoresVendorID(jxcontext.AdminCtx)
if err == nil {
retVal := make([]*model.Store, len(ids))
for index, id := range ids {
store, err2 := p.ReadStore(jxcontext.AdminCtx, id)
if err2 == nil {
retVal[index] = &store.Store
} else {
return nil, err2
}
}
return retVal, nil
}
return nil, err
}
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
globals.SugarLogger.Debugf("jd RefreshAllStoresID")
const stepCount = 3
var stores []*tJdStoreInfo
db := dao.GetDB()
rootTask := tasksch.NewSeqTask("jd RefreshAllStoresID", ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
err = dao.GetRows(db, &stores, `
SELECT t1.*, t2.vendor_store_id
FROM store t1
JOIN store_map t2 ON t1.id = t2.store_id AND t2.deleted_at = ? AND t2.vendor_id = ?
WHERE t1.deleted_at = ?
`, utils.DefaultTimeValue, model.VendorIDJD, utils.DefaultTimeValue)
default:
taskName := "jd RefreshAllStoresID update outSystemId"
if step != stepCount-1 {
taskName = "jd RefreshAllStoresID update to uuid"
}
task1 := tasksch.NewParallelTask(taskName, nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
store := batchItemList[0].(*tJdStoreInfo)
storeParams := map[string]interface{}{
"outSystemId": utils.Int2Str(int(store.ID)),
}
if step != stepCount-1 {
storeParams["outSystemId"] = store.VendorStoreID
}
if globals.EnableJdStoreWrite {
err = getAPI("").UpdateStoreInfo4Open(store.VendorStoreID, ctx.GetUserName(), storeParams)
}
return nil, err
}, stores)
task.AddChild(task1).Run()
_, err = task1.GetResult(0)
}
return nil, err
}, stepCount)
tasksch.HandleTask(rootTask, parentTask, false).Run()
if !isAsync {
_, err = rootTask.GetResult(0)
}
return rootTask.ID, err
}
// func JdRange2JxRange(jdRanges string) (jxRanges string) {
// coords := strings.Split(jdRanges, ";")
// intCoords := []string{}
// for _, coord := range coords {
// items := strings.Split(coord, ",")
// if len(items) == 2 {
// lng := jxutils.StandardCoordinate2Int(utils.Str2Float64(items[0]))
// lat := jxutils.StandardCoordinate2Int(utils.Str2Float64(items[1]))
// intCoords = append(intCoords, fmt.Sprintf("%d,%d", lng, lat))
// }
// }
// return strings.Join(intCoords, ";")
// }
// func JxRange2JdRange(jxRanges string) (jdRanges string) {
// coords := strings.Split(jxRanges, ";")
// intCoords := []string{}
// for _, coord := range coords {
// items := strings.Split(coord, ",")
// if len(items) == 2 {
// lng := jxutils.IntCoordinate2Standard(int(utils.Str2Int64(items[0])))
// lat := jxutils.IntCoordinate2Standard(int(utils.Str2Int64(items[1])))
// intCoords = append(intCoords, fmt.Sprintf("%f,%f", lng, lat))
// }
// }
// return strings.Join(intCoords, ";")
// }
func JdDeliveryType2Jx(deliveryType int) int8 {
if deliveryType == jdapi.CarrierNoSelfDelivery {
return scheduler.StoreDeliveryTypeByStore
} else if deliveryType == jdapi.CarrierNoCrowdSourcing {
return scheduler.StoreDeliveryTypeCrowdSourcing
}
return scheduler.StoreDeliveryTypeByPlatform
}
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, storeID int, vendorStoreID string) (storeStatus int, err error) {
result, err := getAPI("").GetStoreInfoByStationNo(vendorStoreID)
if err == nil {
storeStatus = JdStoreStatus2JxStatus(result["yn"], result["closeStatus"])
}
return storeStatus, err
}
// 当前京东的storeCrud消息不会在门店状态改变时发送所以意义不大先放在这里
func (c *PurchaseHandler) OnStoreMsg(msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) {
var err error
// if msg.StatusID == jdapi.StatusIDUpdateStore {
// var storeStatus int
// vendorStoreID := msg.BillID
// if storeStatus, err = c.GetStoreStatus(jxcontext.AdminCtx, vendorStoreID); err == nil {
// err = partner.CurStoreManager.OnStoreStatusChanged(vendorStoreID, model.VendorIDJD, storeStatus)
// } else {
// // 可能在门店删除的情况下会出查不到门店的错误
// if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == 4 {
// err = nil
// }
// }
// }
return jdapi.Err2CallbackResponse(err, "")
}
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, storeID int, vendorStoreID string, status int) (err error) {
_, closeStatus := JxStoreStatus2JdStatus(status)
if globals.EnableJdStoreWrite {
err = getAPI("").UpdateStoreInfo4Open(vendorStoreID, ctx.GetUserName(), map[string]interface{}{
"closeStatus": closeStatus,
})
}
return err
}
func fillOpTimeParams(params map[string]interface{}, opTimeList []int16) map[string]interface{} {
if params == nil {
params = make(map[string]interface{})
}
index := 1
opTimeListLen := len(opTimeList)
if opTimeListLen > 4 {
opTimeListLen = 4
}
opTimeListLen = opTimeListLen / 2 * 2
for k := 0; k < len(opTimeList); k += 2 {
if opTimeList[k] != 0 {
params[fmt.Sprintf("serviceTimeStart%d", index)] = JxOperationTime2JdOperationTime(int16(opTimeList[k]))
params[fmt.Sprintf("serviceTimeEnd%d", index)] = JxOperationTime2JdOperationTime(int16(opTimeList[k+1]))
} else {
break
}
index++
}
return params
}
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
params := fillOpTimeParams(nil, opTimeList)
if globals.EnableJdStoreWrite {
err = getAPI("").UpdateStoreInfo4Open(vendorStoreID, ctx.GetUserName(), params)
}
return err
}
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context) (vendorStoreIDs []string, err error) {
vendorStoreIDs, err = getAPI("").GetStationsByVenderId()
return vendorStoreIDs, err
}
func (c *PurchaseHandler) storeUploadImgByURL(inImgURL string) (imgURL string, err error) {
if globals.EnableJdStoreWrite {
imgURL, err = api.JdPageAPI.StoreUploadImgByURL(inImgURL)
} else {
imgURL = utils.GetUUID()
}
return imgURL, err
}
func addStoreInfo2Err(err error, storeID int) error {
if err != nil {
errExt := utils.NewErrorCode(err.Error(), "999")
errExt.AddPrefixMsg(fmt.Sprintf("门店%d", storeID))
err = errExt
}
return err
}
func (c *PurchaseHandler) SyncQualify(ctx *jxcontext.Context, storeDetail *dao.StoreDetail) (err error) {
if storeDetail.LicenceCode == "" || storeDetail.Licence == "" {
return addStoreInfo2Err(fmt.Errorf("营业执照信息不全"), storeDetail.ID)
}
if storeDetail.IDCode == "" || storeDetail.IDCardFront == "" || storeDetail.IDCardBack == "" || storeDetail.IDValid == "" {
return addStoreInfo2Err(fmt.Errorf("个人信息不全"), storeDetail.ID)
}
var qualifyList []*jdapi.QualifyItem
licenceDetail, err := api.JdPageAPI.GetCorporationInfo(storeDetail.VendorStoreID, storeDetail.LicenceCode)
if err != nil {
return err
}
licenceURL, err := c.storeUploadImgByURL(storeDetail.Licence)
if err != nil {
return err
}
qualifyList = append(qualifyList, &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeCompany,
QualifyURL: licenceURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(licenceDetail.StartDate)),
QualifyExpireForever: 0,
QualifyName: licenceDetail.OperName,
LicenceType: "-1",
QualifyNumber: storeDetail.LicenceCode,
QualifyAddress: licenceDetail.Address,
LicenceName: licenceDetail.Name,
EconKind: licenceDetail.EconKind,
Scope: licenceDetail.Scope,
})
idFrondURL, err := c.storeUploadImgByURL(storeDetail.IDCardFront)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
// 个体经营,个体工商户
if storeDetail.LicenceType == 0 { // 个人
personQualify := &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypePerson,
QualifyURL: idFrondURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
QualifyNumber: storeDetail.IDCode,
QualifyOwner: storeDetail.LicenceOwnerName,
}
if storeDetail.IDExpire != "" {
personQualify.QualifyExpireForever = 1
personQualify.QualifyExpireEnd = utils.Time2Str(utils.Str2Time(storeDetail.IDExpire))
}
qualifyList = append(qualifyList, personQualify)
} else {
addInfo := &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeAddInfo,
QualifyURL: idFrondURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
}
if storeDetail.IDExpire != "" {
addInfo.QualifyExpireForever = 1
addInfo.QualifyExpireEnd = utils.Time2Str(utils.Str2Time(storeDetail.IDExpire))
}
qualifyList = append(qualifyList, addInfo)
}
if storeDetail.IDExpire == "" {
idBackURL, err := c.storeUploadImgByURL(storeDetail.IDCardBack)
if err != nil {
return addStoreInfo2Err(err, storeDetail.ID)
}
qualifyList = append(qualifyList, &jdapi.QualifyItem{
QualifyType: jdapi.QualifyTypeAddInfo,
QualifyURL: idBackURL,
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
QualifyExpireForever: 0,
})
}
globals.SugarLogger.Debug(utils.Format4Output(qualifyList, false))
if globals.EnableJdStoreWrite {
err = api.JdPageAPI.SaveQualify(storeDetail.VendorStoreID, jdapi.SaveQualifyActionTypeCommit, qualifyList)
// err = api.JdPageAPI.SaveQualify(storeDetail.VendorStoreID, jdapi.SaveQualifyActionTypeSave, qualifyList)
}
return addStoreInfo2Err(err, storeDetail.ID)
}