package ebai import ( "fmt" "strings" "git.rosy.net.cn/baseapi/platformapi/autonavi" "git.rosy.net.cn/baseapi/platformapi/ebaiapi" "git.rosy.net.cn/baseapi/utils" "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" "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/jx-callback/globals/api" ) const ( VendorStorePrefix = "好菜鲜生" ) type tEbaiStoreInfo struct { model.Store VendorStoreID string `orm:"column(vendor_store_id)"` RealLastOperator string EbaiStoreStatus int SyncStatus int ProvinceID int `orm:"column(province_id)"` CityID int `orm:"column(city_id)"` DistrictID int `orm:"column(district_id)"` } func (p *PurchaseHandler) GetFieldIDName() string { return model.FieldEbaiID } func (p *PurchaseHandler) GetFieldSyncStatusName() string { return model.FieldEbaiSyncStatus } func (p *PurchaseHandler) CreateStore(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) { var store tEbaiStoreInfo sql := ` SELECT t1.*, t2.status ebai_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, province.ebai_code province_id, city.ebai_code city_id, district.ebai_code district_id FROM store t1 LEFT JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND t2.deleted_at = ? JOIN place district ON t1.district_code = district.code JOIN place city ON t1.city_code = city.code JOIN place province ON city.parent_code = province.code WHERE t1.id = ? AND t2.id IS NULL; ` if err = dao.GetRow(db, &store, sql, model.VendorIDEBAI, utils.DefaultTimeValue, storeID); err == nil { params := genStoreMapFromStore(&store) params["shop_id"] = store.ID params["business_form_id"] = "179" params["service_phone"] = store.Tel1 params["invoice_support"] = 2 params["package_box_price"] = 0 params["encrypt"] = "" params["category1"] = "" params["category2"] = "" params["category3"] = "" if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite { intVendorStoreID, err2 := api.EbaiAPI.ShopCreate(params) if err = err2; err == nil { return utils.Int64ToStr(intVendorStoreID), err } } else { return utils.Int64ToStr(jxutils.GenFakeID()), nil } } return "", err } func (p *PurchaseHandler) ReadStore(vendorStoreID string) (*model.Store, error) { baiduShopID := utils.Str2Int64(vendorStoreID) result, err := api.EbaiAPI.ShopGet("", baiduShopID) if err == nil { // globals.SugarLogger.Debug(utils.Format4Output(result, false)) retVal := &model.Store{ Address: utils.Interface2String(result["address"]), Tel1: utils.Interface2String(result["phone"]), } _, retVal.Name = jxutils.SplitStoreName(utils.Interface2String(result["name"]), partner.StoreNameSeparator, VendorStorePrefix) retVal.DeliveryType = EbaiDeliveryType2Jx(utils.Interface2String(result["delivery_type"])) businessTime := result["business_time"].([]interface{}) btime := businessTime[0].(map[string]interface{}) retVal.OpenTime1 = jxutils.StrTime2JxOperationTime(utils.Interface2String(btime["start"].(string)), 700) retVal.CloseTime1 = jxutils.StrTime2JxOperationTime(utils.Interface2String(btime["end"].(string)), 2000) if len(businessTime) > 1 { btime = businessTime[1].(map[string]interface{}) retVal.OpenTime2 = jxutils.StrTime2JxOperationTime(utils.Interface2String(btime["start"].(string)), 700) retVal.CloseTime2 = jxutils.StrTime2JxOperationTime(utils.Interface2String(btime["end"].(string)), 2000) } if ebaiStatus, err2 := api.EbaiAPI.ShopBusStatusGet("", baiduShopID, ebaiapi.PlatformFlagBaidu); err2 == nil { retVal.Status = EbaiBusStatus2JxStatus(ebaiStatus) } tel2 := utils.Interface2String(result["ivr_phone"]) if tel2 != "" && tel2 != retVal.Tel1 { retVal.Tel2 = tel2 } db := dao.GetDB() if city, err2 := dao.GetPlaceByName(db, utils.Interface2String(result["city"]), model.PlaceLevelCity, 0); err2 == nil { retVal.CityCode = city.Code if district, err2 := dao.GetPlaceByName(db, utils.Interface2String(result["county"]), model.PlaceLevelDistrict, city.Code); err2 == nil { retVal.DistrictCode = district.Code } } lng := utils.MustInterface2Float64(result["longitude"]) lat := utils.MustInterface2Float64(result["latitude"]) if utils.Interface2String(result["coord_type"]) == ebaiapi.CoordTypeBaidu { var err2 error if lng, lat, err2 = api.AutonaviAPI.CoordinateConvert(lng, lat, autonavi.CoordSysBaidu); err2 != nil { return nil, err2 } } retVal.Lng = jxutils.StandardCoordinate2Int(lng) retVal.Lat = jxutils.StandardCoordinate2Int(lat) retVal.ID = int(utils.Str2Int64WithDefault(utils.Interface2String(result["shop_id"]), 0)) retVal.DeliveryRangeType = model.DeliveryRangeTypePolygon retVal.DeliveryRange = EbaiDeliveryRegion2Jx(result["delivery_region"]) return retVal, nil } return nil, err } func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) { var stores []*tEbaiStoreInfo sql := ` SELECT t1.*, t2.status ebai_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 = ? OR t2.sync_status <> 0) WHERE t1.id = ? ORDER BY t2.updated_at ` if err = dao.GetRows(db, &stores, sql, model.VendorIDEBAI, utils.DefaultTimeValue, storeID); err == nil { for _, store := range stores { params := genStoreMapFromStore(store) // globals.SugarLogger.Debug(utils.Format4Output(params, false)) if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite { if err = api.EbaiAPI.ShopUpdate(params); err == nil { shopID := 0 if store.SyncStatus&model.SyncFlagDeletedMask == 0 { shopID = store.ID } store2, err2 := p.ReadStore(store.VendorStoreID) if err = err2; err == nil { if store2.ID == store.ID { shopID = -1 } } if err == nil { if shopID > 0 { err = api.EbaiAPI.ShopIDBatchUpdate([]string{store.VendorStoreID}, []string{utils.Int2Str(shopID)}) } else if shopID == 0 { // todo remove out shop id } } if err == nil { mergeStatus := jxutils.MergeStoreStatus(store.Status, store.EbaiStoreStatus) if mergeStatus == model.StoreStatusOpened { err = api.EbaiAPI.ShopOnline("", utils.Str2Int64(store.VendorStoreID)) } else if mergeStatus == model.StoreStatusClosed { err = api.EbaiAPI.ShopOffline("", utils.Str2Int64(store.VendorStoreID)) } else if mergeStatus == model.StoreStatusClosed { err = api.EbaiAPI.ShopClose("", utils.Str2Int64(store.VendorStoreID)) } if err != nil { return err } } } } } } return err } func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) { globals.SugarLogger.Debugf("ebai RefreshAllStoresID") const batchSize = 50 const stepCount = 3 var stores []*tEbaiStoreInfo db := dao.GetDB() rootTask := tasksch.NewSeqTask("ebai RefreshAllStoresID", ctx.GetUserName(), 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.VendorIDEBAI, utils.DefaultTimeValue) default: taskName := "ebai RefreshAllStoresID update to custom id" if step != stepCount-1 { taskName = "ebai RefreshAllStoresID update to uuid" } task1 := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetBatchSize(batchSize), ctx.GetUserName(), func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { baiduShopIDs := make([]string, len(batchItemList)) shopIDs := make([]string, len(batchItemList)) for k, v := range batchItemList { store := v.(*tEbaiStoreInfo) baiduShopIDs[k] = store.VendorStoreID shopIDs[k] = utils.Int2Str(store.ID) if step != stepCount-1 { shopIDs[k] = utils.GetUUID() } } if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite { err = api.EbaiAPI.ShopIDBatchUpdate(baiduShopIDs, shopIDs) } return nil, err }, stores) task.AddChild(task1).Run() _, err = task1.GetResult(0) } return nil, err }, stepCount) ctx.SetTaskOrAddChild(rootTask, parentTask) rootTask.Run() if !isAsync { _, err = rootTask.GetResult(0) } return rootTask.ID, err } func EbaiDeliveryType2Jx(deliveryType string) int8 { spIndex := strings.Index(deliveryType, "|") baiduDeliveryType := utils.Str2Int64(deliveryType[spIndex+1:]) switch baiduDeliveryType { case ebaiapi.DeliveryTypeBaiduLogistics: return scheduler.StoreDeliveryTypeByPlatform case ebaiapi.DeliveryTypeBaiduDeliveryBySelf: return scheduler.StoreDeliveryTypeByStore case ebaiapi.DeliveryTypeBaiduCrowdSourcing: return scheduler.StoreDeliveryTypeCrowdSourcing default: return scheduler.StoreDeliveryTypeCrowdSourcing } } func EbaiDeliveryRegion2Jx(deliveryRegion interface{}) string { realDeliveryRegion := deliveryRegion.([]interface{}) if len(realDeliveryRegion) > 0 { region := deliveryRegion.([]interface{})[0].(map[string]interface{})["region"].([]interface{})[0].([]interface{}) coords := make([]string, len(region)) for k, v := range region { mapV := v.(map[string]interface{}) coords[k] = fmt.Sprintf("%.6f,%.6f", utils.MustInterface2Float64(mapV["longitude"]), utils.MustInterface2Float64(mapV["latitude"])) } return strings.Join(coords, ";") } return "" } func JxDeliveryRegion2Ebai(store *model.Store) interface{} { rangeStr := store.DeliveryRange if store.DeliveryRangeType == model.DeliveryRangeTypeRadius { rangeStr = jxutils.GetPolygonFromCircleStr(jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat), utils.Str2Float64(store.DeliveryRange), 8) } pointPairs := strings.Split(rangeStr, ";") region := make([]map[string]interface{}, len(pointPairs)) for k, v := range pointPairs { pointPair := strings.Split(v, ",") region[k] = map[string]interface{}{ "longitude": utils.Str2Float64(pointPair[0]), "latitude": utils.Str2Float64(pointPair[1]), } } deliveryRegion := []interface{}{ map[string]interface{}{ "name": "主要配送区", "delivery_fee": 600, "delivery_time": "60", "min_buy_free": "0", "min_order_price": "0", "region": []interface{}{ region, }, }, } return deliveryRegion } func JxBusinessTime2Ebai(store *model.Store) interface{} { bTime := make([]map[string]interface{}, 1) bTime[0] = map[string]interface{}{ "start": jxutils.JxOperationTime2StrTime(store.OpenTime1), "end": jxutils.JxOperationTime2StrTime(store.CloseTime1), } if store.OpenTime2 != 0 { bTime = append(bTime, map[string]interface{}{ "start": jxutils.JxOperationTime2StrTime(store.OpenTime2), "end": jxutils.JxOperationTime2StrTime(store.CloseTime2), }) } return bTime } func genStoreMapFromStore(store *tEbaiStoreInfo) map[string]interface{} { params := map[string]interface{}{ "name": jxutils.ComposeStoreName(store.Name, partner.StoreNameSeparator, VendorStorePrefix), "phone": store.Tel1, "longitude": jxutils.IntCoordinate2Standard(store.Lng), "latitude": jxutils.IntCoordinate2Standard(store.Lat), "address": store.Address, "coord_type": ebaiapi.CoordTypeAutonavi, // 一直用高德 "delivery_region": JxDeliveryRegion2Ebai(&store.Store), "business_time": JxBusinessTime2Ebai(&store.Store), } if store.VendorStoreID != "" { params["baidu_shop_id"] = store.VendorStoreID } if store.Tel2 != "" { params["ivr_phone"] = store.Tel2 } if store.ProvinceID != 0 { params["province"] = store.ProvinceID } if store.CityID != 0 { params["city"] = store.CityID } if store.DistrictID != 0 { params["county"] = store.DistrictID } return params }