@@ -4,14 +4,19 @@ import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
product_addV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_addV2/request"
"git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api"
"git.rosy.net.cn/jx-callback/business/jxutils"
"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/business/partner/purchase/mtwm"
"git.rosy.net.cn/jx-callback/business/partner/purchase/tiktok_store"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
beego "github.com/astaxie/beego/server/web"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
@@ -50,6 +55,14 @@ func CopyOnStoreSkuToOther(ctx *jxcontext.Context, fromStoreId, toStoreId string
_ , copySkuErr , err = CopyMtToMT ( ctx , fromStore , toStore , isAsync , offSet )
case model . VendorIDEBAI :
_ , copySkuErr , err = CopyEBaiToEBai ( ctx , fromStore , toStore , isAsync , offSet )
case 114 : // 美团到抖音
_ , copySkuErr , err = CopyMtToTiktok ( ctx , fromStore , toStore , isAsync , offSet )
case 13 : // 美团到饿了么
_ , copySkuErr , err = CopyMtToEBai ( ctx , fromStore , toStore , isAsync , offSet )
case 31 : // 饿了么到美团
_ , copySkuErr , err = CopyEBaiToMt ( ctx , fromStore , toStore , isAsync , offSet )
case 10 : // 美团到京东
default :
return nil , fmt . Errorf ( "暂时还不支持" )
}
@@ -64,7 +77,7 @@ func CopyOnStoreSkuToOther(ctx *jxcontext.Context, fromStoreId, toStoreId string
return copySkuErr , err
}
//#region 同步商品
//#region 饿百 同步商品
// CopyEBaiToEBai 饿了么商品复制到饿了么
func CopyEBaiToEBai ( ctx * jxcontext . Context , fromStore , toStore * dao . StoreDetail , isAsync bool , offset int ) ( hint string , errList [ ] string , err error ) {
@@ -180,10 +193,14 @@ func BatchInitSkuEBai2EBai(ctx *jxcontext.Context, fromSku []*ebaiapi.SkuInfo, t
return errList
}
//#endregion
//#region 美团同步商品
// CopyMtToMT 美团商品复制到美团
func CopyMtToMT ( ctx * jxcontext . Context , fromStore , toStore * dao . StoreDetail , isAsync bool , offSet int ) ( hint string , data [ ] string , err error ) {
var fromApi * mtwmapi . API //= mtwm.GetAPI(fromStore.VendorOrgCode, fromStore.ID, fromStore.VendorStoreID)
var toApi * mtwmapi . API // = mtwm.GetAPI(toStore.VendorOrgCode, toStore.ID, toStore.VendorStoreID)
var fromApi * mtwmapi . API
var toApi * mtwmapi . API
var errList = make ( [ ] * mtwmapi . AppFoodResult , 0 , 0 )
var errData = make ( [ ] string , 0 , 0 )
@@ -207,35 +224,35 @@ func CopyMtToMT(ctx *jxcontext.Context, fromStore, toStore *dao.StoreDetail, isA
switch step {
case 1 :
// 同步分类
// fromCategoryList, err := fromApi. RetailCatList( fromStore. VendorStoreID)
//if len(fromCategoryList) == model.NO {
fromCategoryList, err := fromApi. RetailCatList( fromStore. VendorStoreID )
if len ( fromCategoryList ) == model . NO {
return nil , err
}
//toCategoryList, err := toApi.RetailCatList(toStore.VendorStoreID)
//if err != nil {
// return nil, err
//}
////toCategoryList, err := toApi.RetailCatList(toStore.VendorStoreID)
////if err != nil {
//// return nil, err
////}
//for _, v := range fromCategoryList {
// categoryErr := toApi.RetailCatUpdate(toStore.VendorStoreID, v.Name, &mtwmapi.Param4UpdateCat {
// CategoryCode: v.Code,
// Sequence: v.Sequence,
// })
// if categoryErr != nil {
// globals.SugarLogger.Debugf("err := RetailCatUpdate : %v", categoryErr)
// }
// if v.Children != nil && len(v.Children) != 0 {
// for _, c := range v.Children {
// if err3 := toApi.RetailCatUpdate(toStore.VendorStoreID, v.Name, &mtwmapi.Param4UpdateCat{
// CategoryNameOrigin: v.Name,
// SecondaryCategoryCode: c.Code,
// SecondaryCategoryName: c.Name,
// Sequence: c.Sequence,
// }); err3 != nil {
// globals.SugarLogger.Debugf("err := RetailCatUpdate Children : %v", err3)
// }
// }
// }
//}
for _ , v := range fromCategoryList {
categoryErr := toApi . RetailCatUpdate ( toStore . VendorStoreID , v . Name , & mtwmapi . Param4UpdateCat {
CategoryCode : v . Code ,
Sequence : v . Sequence ,
} )
if categoryErr != nil {
globals . SugarLogger . Debugf ( "err := RetailCatUpdate : %v" , categoryErr )
}
if v . Children != nil && len ( v . Children ) != 0 {
for _ , c := range v . Children {
if err3 := toApi . RetailCatUpdate ( toStore . VendorStoreID , v . Name , & mtwmapi . Param4UpdateCat {
CategoryNameOrigin : v . Name ,
SecondaryCategoryCode : c . Code ,
SecondaryCategoryName : c . Name ,
Sequence : c . Sequence ,
} ) ; err3 != nil {
globals . SugarLogger . Debugf ( "err := RetailCatUpdate Children : %v" , err3 )
}
}
}
}
case 2 :
i := offSet
@@ -462,6 +479,743 @@ func createCommonAttrValue(apiObj *mtwmapi.API, tempCatID int64, name string) (s
//#endregion
//#region 美团同步到抖音商品
// CopyMtToTiktok 复制美团商品到抖音
func CopyMtToTiktok ( ctx * jxcontext . Context , fromStore , toStore * dao . StoreDetail , isAsync bool , offSet int ) ( hint string , data [ ] string , err error ) {
var fromApi * mtwmapi . API //= mtwm.GetAPI(fromStore.VendorOrgCode, fromStore.ID, fromStore.VendorStoreID)
var toApi = partner . CurAPIManager . GetAPI ( model . VendorIDDD , toStore . VendorOrgCode ) . ( * tiktok_api . API )
var errList = make ( [ ] * mtwmapi . AppFoodResult , 0 , 0 )
var errData = make ( [ ] string , 0 , 0 )
if fromStore . VendorOrgCode == globals . Mtwm2Code {
fromApi = mtwmapi . New ( beego . AppConfig . DefaultString ( "mtwmAppID2" , "" ) , beego . AppConfig . DefaultString ( "mtwmSecret2" , "" ) , beego . AppConfig . DefaultString ( "mtwmCallbackURL2" , "" ) , "" )
fromApi . SetToken ( fromStore . MtwmToken )
} else {
fromApi = partner . CurAPIManager . GetAPI ( model . VendorIDMTWM , fromStore . VendorOrgCode ) . ( * mtwmapi . API )
}
taskName := fmt . Sprintf ( "将美团平台门店[%s],分类和商品复制到抖音[%s]" , fromStore . VendorStoreID , toStore . VendorStoreID )
config := tasksch . NewParallelConfig ( ) . SetParallelCount ( 1 ) . SetIsContinueWhenError ( false )
work := func ( task * tasksch . ParallelTask , batchItemList [ ] interface { } , params ... interface { } ) ( retVal interface { } , err error ) {
step := batchItemList [ 0 ] . ( int )
switch step {
case 1 :
case 2 :
i := offSet
for {
// 同步商品
fromFoodList , err1 := fromApi . RetailListAll ( fromStore . VendorStoreID , i )
if len ( fromFoodList ) == 0 || fromFoodList == nil {
return nil , fmt . Errorf ( "fromFoodList 为空 %s ,i:= %d" , utils . Format4Output ( err1 , false ) , i )
}
errDataList , err := BatchInitSkuMT2TT ( ctx , fromFoodList , fromStore . VendorStoreID , toApi , toStore , i )
if err != nil {
globals . SugarLogger . Debugf ( "BatchInitData : %v" , err )
}
if len ( errDataList ) > model . NO {
globals . SugarLogger . Debugf ( "errListData %d:= %s" , i , utils . Format4Output ( errDataList , false ) )
errList = append ( errList , errDataList ... )
}
globals . SugarLogger . Debugf ( "==========页数[%d],数据长度[%d]" , i , len ( fromFoodList ) )
if len ( fromFoodList ) < 100 {
break
}
i ++
}
}
return
}
task := tasksch . NewParallelTask ( taskName , config , ctx , work , [ ] int { 1 , 2 } )
tasksch . HandleTask ( task , nil , true ) . Run ( )
if ! isAsync {
_ , err = task . GetResult ( 0 )
hint = "1"
} else {
hint = task . ID
}
globals . SugarLogger . Debugf ( "======errrList := %s" , utils . Format4Output ( errList , false ) )
for _ , v := range errList {
errData = append ( errData , fmt . Sprintf ( "food_id:%s,错误:%s" , v . AppFoodCode , v . ErrorMsg ) )
}
return hint , errData , err
}
var StoreTemp = make ( map [ string ] string , 0 )
// BatchInitSkuMT2TT 批量创建商品美团->抖音
func BatchInitSkuMT2TT ( ctx * jxcontext . Context , fromSku [ ] * mtwmapi . AppFood , fromStoreId string , toApi * tiktok_api . API , toStoreDetail * dao . StoreDetail , offset int ) ( [ ] * mtwmapi . AppFoodResult , error ) {
errList := make ( [ ] * mtwmapi . AppFoodResult , 0 , 0 )
db := dao . GetDB ( )
copyMap , _ := dao . GetCopyInfo ( fromStoreId , model . VendorIDMTWM , toStoreDetail . VendorStoreID , model . VendorIDDD )
for k , storeSku := range fromSku {
if storeSku . AppFoodCode == "" {
storeSku . AppFoodCode = fmt . Sprintf ( "%d_%d" , storeSku . Ctime , k )
}
// 没查询到主品创建记录,创建主品
if copyMap [ storeSku . AppFoodCode ] == nil || copyMap [ storeSku . AppFoodCode ] . MainSkuId == "" {
param := & product_addV2_request . ProductAddV2Param {
Name : utils . LimitUTF8StringLen ( storeSku . Name , 90 ) ,
PayType : tiktok_api . TiktokPayType1 ,
ReduceType : tiktok_api . SkuReduceTypePayMakeOrder ,
DeliveryDelayDay : tiktok_api . DeliveryDelayDayToDay ,
PresellType : tiktok_api . SendGoodsTypeNow ,
Supply7dayReturn : 0 , // 是否支持7天无理由, 0不支持, 1支持, 2支持( 拆封后不支持)
Mobile : toStoreDetail . Tel1 ,
Commit : true ,
//Specs: "重量|" + utils.Float64ToStr(float64(storeSku.SpecQuality)) + storeSku.SpecUnit,
NeedRechargeMode : false ,
SellChannel : [ ] int64 { 0 } ,
StartSaleType : 0 ,
PickupMethod : "0" ,
OuterProductId : storeSku . AppFoodCode , // 本地skuId为外部商品id
}
specs := "重量|"
specsList := make ( [ ] string , 0 , 0 )
upc := ""
for _ , sl := range storeSku . SkuList {
specsList = append ( specsList , strings . Split ( sl . Spec , "*" ) [ 0 ] )
param . Weight = utils . Str2Float64 ( sl . Weight )
upc = sl . Upc
}
param . Specs = specs + strings . Join ( specsList , "," )
// 获取上传图,商品轮播图
imgs := make ( [ ] tiktok_api . Imgs , 0 , 0 )
for spk , spl := range storeSku . PictureList {
switch spk {
case 0 :
imgs = append ( imgs , tiktok_api . Imgs {
Name : "white_" + utils . Int2Str ( toStoreDetail . ID ) + "_" + spl [ 21 : 54 ] ,
Url : spl ,
} )
case len ( storeSku . PictureList ) - 1 :
imgs = append ( imgs , tiktok_api . Imgs {
Name : "detail_" + utils . Int2Str ( toStoreDetail . ID ) + "_" + spl [ 21 : 54 ] ,
Url : spl ,
} )
default :
imgs = append ( imgs , tiktok_api . Imgs {
Name : utils . Int2Str ( toStoreDetail . ID ) + "_" + spl [ 21 : 54 ] ,
Url : spl ,
} )
}
}
tiktokImgList , err := toApi . BatchUploadImages ( imgs )
if err != nil {
errList = append ( errList , & mtwmapi . AppFoodResult {
AppFoodCode : storeSku . AppFoodCode ,
ErrorMsg : fmt . Sprintf ( "%s:%s,图片上传错误" , storeSku . Name , err . Error ( ) ) ,
} )
continue
}
picList := make ( [ ] string , 0 , 0 )
for til , v := range tiktokImgList {
if strings . Contains ( til , "detail_" ) {
param . Description = v . ByteUrl
continue
}
if strings . Contains ( til , "white_" ) {
param . WhiteBackGroundPicUrl = v . ByteUrl
}
picList = append ( picList , v . ByteUrl )
}
param . Pic = strings . Join ( picList , "|" )
// 自动推导分类id
if len ( param . Pic ) != 0 {
var vendorCategoryId int64 = 0
// 根据图片推导分类
picList = append ( picList , param . WhiteBackGroundPicUrl , param . Description )
vendorCategoryId , _ = toApi . GetRecommendCategory ( picList )
// 根据名字推导分类
if vendorCategoryId == 0 {
vendorCategoryId , _ = toApi . GetRecommendCategoryByName ( param . Name )
}
if vendorCategoryId == 0 || err != nil {
errList = append ( errList , & mtwmapi . AppFoodResult {
AppFoodCode : storeSku . AppFoodCode ,
ErrorMsg : fmt . Sprintf ( "%s:%s,自动推导分类错误" , storeSku . Name , err . Error ( ) ) ,
} )
continue
}
param . CategoryLeafId = vendorCategoryId
}
// 是否支持七天无理由
if toApi . GetProductUpdateRule ( param . CategoryLeafId ) {
param . Supply7dayReturn = 1
} else {
param . Supply7dayReturn = 0
}
// weight_unit 目前抖音只支持g和kg两种
param . WeightUnit = tiktok_api . WeightUint_G
// spec_prices
//param.SpecPrices = GetSpecPrices(param.Specs, vendorStoreID, 0, storeSku)
skuSize := make ( [ ] * tiktok_api . SpecDetailList , 0 , 0 )
name1 := strings . Split ( strings . Split ( param . Specs , "|" ) [ 1 ] , "," )
for _ , sl := range storeSku . SkuList {
for i := 0 ; i < len ( name1 ) ; i ++ {
if name1 [ i ] == strings . Split ( sl . Spec , "*" ) [ 0 ] {
sku := & tiktok_api . SpecDetailList {
SpecDetailName1 : name1 [ i ] ,
Price : utils . Float64TwoInt ( utils . Str2Float64 ( sl . Price ) ) ,
Code : storeSku . AppFoodCode + fmt . Sprintf ( "_%d" , i ) ,
StepStockNum : 0 ,
SupplierID : "" ,
OuterSkuID : storeSku . AppFoodCode + fmt . Sprintf ( "_%d" , i ) ,
}
sku . DeliveryInfos = [ ] * tiktok_api . DeliveryInfos {
{ InfoType : "weight" , InfoUnit : name1 [ i ] [ len ( name1 [ i ] ) - 1 : ] , InfoValue : name1 [ i ] } ,
}
sku . StockNum = utils . Str2Int ( sl . Stock )
sku . SkuType = 1
sku . StockNumMap = map [ string ] int64 { toStoreDetail . VendorStoreID : int64 ( sku . StockNum ) }
skuSize = append ( skuSize , sku )
}
}
}
data , _ := json . Marshal ( skuSize )
param . SpecPrices = string ( data )
// 获取商品的属性
//param.ProductFormatNew, param.StandardBrandId, err = MakeProductFormatNew(api, int64(storeSku.NameID), param.CategoryLeafId, storeSku.Upc, storeSku.UpcBrandName, storeSku.UpcTiktokBrandId)
if upc == "" {
param . StandardBrandId = 596120136
} else {
brandName , err := tiktok_store . GetBrandByBrandName ( upc )
if err != nil {
param . StandardBrandId = 596120136
} else {
if strings . Contains ( brandName , "/" ) || strings . Contains ( brandName , "(" ) || strings . Contains ( brandName , "( " ) {
brandName = strings . Split ( brandName , "/" ) [ 0 ]
}
if strings . Contains ( brandName , "(" ) {
brandName = strings . Split ( brandName , "(" ) [ 0 ]
}
if strings . Contains ( brandName , "( " ) {
brandName = strings . Split ( brandName , "( " ) [ 0 ]
}
standardBrandId , err := toApi . GetSkuBrand ( param . CategoryLeafId , brandName )
if err != nil {
param . StandardBrandId = 596120136
} else {
param . StandardBrandId = standardBrandId
}
}
}
if param . StandardBrandId == 0 {
param . StandardBrandId = 596120136
}
categoryList , err := toApi . GetCatePropertyV2 ( param . CategoryLeafId )
if err != nil {
errList = append ( errList , & mtwmapi . AppFoodResult {
AppFoodCode : storeSku . AppFoodCode ,
ErrorMsg : fmt . Sprintf ( "%s:%s,根据商品分类推导属性错误" , storeSku . Name , err . Error ( ) ) ,
} )
continue
}
categoryMap := make ( map [ string ] [ ] map [ string ] interface { } )
for _ , v := range categoryList . Data . Data {
if v . Required != model . YES {
continue
}
options := make ( [ ] map [ string ] interface { } , 0 )
if v . PropertyName == "品牌" {
options = append ( options , map [ string ] interface { } { "name" : v . PropertyName , "value" : param . StandardBrandId , "diy_type" : v . DiyType } )
categoryMap [ utils . Int64ToStr ( v . PropertyId ) ] = options
} else if v . PropertyName == "产地" {
options = append ( options , map [ string ] interface { } { "name" : v . PropertyName , "value" : 13850 , "diy_type" : v . DiyType } )
categoryMap [ utils . Int64ToStr ( v . PropertyId ) ] = options
} else if len ( options ) == 0 {
options = append ( options , map [ string ] interface { } { "name" : v . PropertyName , "value" : 0 , "diy_type" : v . DiyType } )
categoryMap [ utils . Int64ToStr ( v . PropertyId ) ] = options
} else {
options = append ( options , map [ string ] interface { } { "name" : v . PropertyName , "value" : v . Options [ 0 ] . Value , "diy_type" : v . DiyType } )
categoryMap [ utils . Int64ToStr ( v . PropertyId ) ] = options
}
}
param . ProductFormatNew = utils . Format4Output ( categoryMap , false )
//param.ProductFormatNew, err = MakeProductFormatNew(api, int64(storeSku.NameID), param.CategoryLeafId)
if StoreTemp [ toStoreDetail . VendorStoreID ] != "" {
idList := strings . Split ( StoreTemp [ toStoreDetail . VendorStoreID ] , "_" )
param . FreightId , param . SaleLimitId = utils . Str2Int64 ( idList [ 0 ] ) , utils . Str2Int64 ( idList [ 1 ] )
} else {
// 运费模板
param . FreightId , err = tiktok_store . GetDeliveryTemp ( toApi , toStoreDetail . VendorStoreID , toStoreDetail )
if err != nil {
errList = append ( errList , & mtwmapi . AppFoodResult {
AppFoodCode : storeSku . AppFoodCode ,
ErrorMsg : fmt . Sprintf ( "%s:%s,运费模版获取错误" , storeSku . Name , err . Error ( ) ) ,
} )
return errList , nil
}
// 获取门店限售模板
param . SaleLimitId , err = tiktok_store . CreateSaleTemp ( utils . Str2Int64 ( toStoreDetail . VendorStoreID ) , toApi )
if err != nil {
errList = append ( errList , & mtwmapi . AppFoodResult {
AppFoodCode : storeSku . AppFoodCode ,
ErrorMsg : fmt . Sprintf ( "%s:%s,限售模版获取错误" , storeSku . Name , err . Error ( ) ) ,
} )
return errList , nil
}
StoreTemp [ toStoreDetail . VendorStoreID ] = fmt . Sprintf ( "%d_%d" , param . FreightId , param . SaleLimitId )
}
tiktokResult , errCreate := toApi . CreateStoreCommodity ( param ) // 创建主商品,同步主商品
copyData := & model . CopyVendorSku {
FromSkuID : storeSku . AppPoiCode ,
FromSkuName : storeSku . Name ,
FromStoreId : fromStoreId ,
FromVendorId : model . VendorIDMTWM ,
ToStoreId : toStoreDetail . VendorStoreID ,
ToVendorId : model . VendorIDDD ,
MainSkuId : "" ,
ChildrenSkuId : "" ,
ErrMsg : "" ,
}
if errCreate != nil {
copyData . ErrMsg = errCreate . Error ( )
}
if tiktokResult . ProductId != 0 {
copyData . MainSkuId = utils . Int64ToStr ( tiktokResult . ProductId )
}
dao . CreateEntity ( db , copyData )
} else {
// 主商品存在,直接同步子商品
childrenProductId , err := toApi . CreateSubProduct ( utils . Str2Int64 ( copyMap [ storeSku . AppPoiCode ] . MainSkuId ) , utils . Str2Int64 ( toStoreDetail . VendorStoreID ) )
// 2010004:主商品非在线审核通过状态,不允许绑定子商品
if err != nil && strings . Contains ( err . Error ( ) , "2010004" ) {
// 线上本地都存在,但是线上审核不成功,就去更新主商品
copyMap [ storeSku . AppPoiCode ] . ErrMsg = err . Error ( )
dao . UpdateEntity ( db , copyMap [ storeSku . AppPoiCode ] , "ErrMsg" )
continue
}
if err != nil && strings . Contains ( err . Error ( ) , "2010001" ) { // 2010001:重复创建渠道商品
storeSkuDetail , err := toApi . GetSkuDetailLocalID ( toStoreDetail . VendorStoreID , storeSku . AppFoodCode )
if err != nil {
copyMap [ storeSku . AppPoiCode ] . ErrMsg = err . Error ( )
dao . UpdateEntity ( db , copyMap [ storeSku . AppPoiCode ] , "ErrMsg" )
continue
}
childrenProductId = storeSkuDetail . ProductId
copyMap [ storeSku . AppPoiCode ] . ChildrenSkuId = utils . Int64ToStr ( childrenProductId )
dao . UpdateEntity ( db , copyMap [ storeSku . AppPoiCode ] , "ChildrenSkuId" )
}
if childrenProductId != model . NO {
// 同步价格,库存,上架
//childrenDetail, err := toApi.GetSkuDetail(utils.Int64ToStr(childrenProductId), "")
//if err != nil {
// copyMap[storeSku.AppPoiCode].ErrMsg = err.Error()
// dao.UpdateEntity(db, copyMap[storeSku.AppPoiCode], "ErrMsg")
// continue
//}
//for _, v := range childrenDetail.SpecPrices {
// childrenSkuId := v.SkuId
// storeSku.VendorSonSkuID = utils.Int64ToStr(childrenSkuId)
// return childrenSkuId, nil
//}
//failedList2 := upDateChildrenPriceStockLaunch(api, storeSku, childrenProductId, vendorStoreID, syncType)
if err := toApi . LaunchProduct ( childrenProductId ) ; err != nil {
copyMap [ storeSku . AppPoiCode ] . ErrMsg = "上架失败" + err . Error ( )
dao . UpdateEntity ( db , copyMap [ storeSku . AppPoiCode ] , "ChildrenSkuId" )
}
}
}
}
return errList , nil
}
//#endregion
//#region 美团同步到饿百
// CopyMtToEBai 复制美团商品到饿百
func CopyMtToEBai ( ctx * jxcontext . Context , fromStore , toStore * dao . StoreDetail , isAsync bool , offSet int ) ( hint string , data [ ] string , err error ) {
VendorCategoryIDMap := map [ string ] int64 { }
var fromApi * mtwmapi . API //= mtwm.GetAPI(fromStore.VendorOrgCode, fromStore.ID, fromStore.VendorStoreID)
var ebaiApi = api . EbaiAPI
var errListData = make ( [ ] string , 0 , 0 )
if fromStore . VendorOrgCode == globals . Mtwm2Code {
fromApi = mtwmapi . New ( beego . AppConfig . DefaultString ( "mtwmAppID2" , "" ) , beego . AppConfig . DefaultString ( "mtwmSecret2" , "" ) , beego . AppConfig . DefaultString ( "mtwmCallbackURL2" , "" ) , "" )
fromApi . SetToken ( fromStore . MtwmToken )
} else {
fromApi = partner . CurAPIManager . GetAPI ( model . VendorIDMTWM , fromStore . VendorOrgCode ) . ( * mtwmapi . API )
}
taskName := fmt . Sprintf ( "将美团平台门店[%s],分类和商品复制到饿百[%s]" , fromStore . VendorStoreID , toStore . VendorStoreID )
config := tasksch . NewParallelConfig ( ) . SetParallelCount ( 1 ) . SetIsContinueWhenError ( false )
work := func ( task * tasksch . ParallelTask , batchItemList [ ] interface { } , params ... interface { } ) ( retVal interface { } , err error ) {
step := batchItemList [ 0 ] . ( int )
switch step {
case 1 :
// 1.加载门店商品,删除商品.当分类下没有商品时.删除分类
//errs := LoadingStoreSkuList(ctx, toApi, toStore.VendorStoreID)
// errs := LoadingStoreSkuList(ctx, toApi, toStore.VendorStoreID)
//if errs != nil && len(errs) > 0 {
// return nil, errs[0]
//}
case 2 :
//同步分类
fromCategoryList , err := fromApi . RetailCatList ( fromStore . VendorStoreID )
if len ( fromCategoryList ) == model . NO {
return nil , err
}
for k , v := range fromCategoryList {
parentID , categoryErr := ebaiApi . ShopCategoryCreate ( utils . Int2Str ( toStore . ID ) , 0 , v . Name , len ( fromCategoryList ) - k )
if categoryErr != nil {
globals . SugarLogger . Debugf ( "err := RetailCatUpdate : %v" , categoryErr )
continue
}
if v . Code == "" {
VendorCategoryIDMap [ v . Name ] = parentID
} else {
VendorCategoryIDMap [ v . Code ] = parentID
}
if v . Children != nil && len ( v . Children ) != 0 {
for _ , c := range v . Children {
childrenCateId , err := ebaiApi . ShopCategoryCreate ( utils . Int2Str ( toStore . ID ) , parentID , c . Name , len ( v . Children ) - k )
if err != nil {
globals . SugarLogger . Debugf ( "err := RetailCatUpdate Children : %v" , err )
continue
}
if c . Code == "" {
VendorCategoryIDMap [ c . Name ] = childrenCateId
} else {
VendorCategoryIDMap [ c . Code ] = childrenCateId
}
}
}
}
case 3 :
i := offSet
for {
// 同步商品
fromFoodList , err1 := fromApi . RetailListAll ( fromStore . VendorStoreID , i )
if len ( fromFoodList ) == 0 || fromFoodList == nil {
return nil , fmt . Errorf ( "fromFoodList 为空 %s ,i:= %d" , utils . Format4Output ( err1 , false ) , i )
}
errList := BatchInitSkuMtwm2EBai ( ctx , fromFoodList , ebaiApi , utils . Int2Str ( toStore . ID ) , VendorCategoryIDMap )
if errList != nil {
for _ , err2 := range errList {
errListData = append ( errListData , err2 . Error ( ) )
}
globals . SugarLogger . Debugf ( "BatchInitData : %s" , utils . Format4Output ( errList , false ) )
}
i = i + 1
}
}
return
}
task := tasksch . NewParallelTask ( taskName , config , ctx , work , [ ] int { 1 , 2 , 3 } )
tasksch . HandleTask ( task , nil , true ) . Run ( )
if ! isAsync {
_ , err = task . GetResult ( 0 )
hint = "1"
} else {
hint = task . ID
}
return hint , errListData , err
}
// BatchInitSkuMtwm2EBai 批量创建商品美团到饿百
func BatchInitSkuMtwm2EBai ( ctx * jxcontext . Context , fromSku [ ] * mtwmapi . AppFood , toApi * ebaiapi . API , storeID string , VendorCategoryIDMap map [ string ] int64 ) [ ] error {
var errList = make ( [ ] error , 0 , 0 )
for k , storeSku := range fromSku {
params := map [ string ] interface { } { }
photos := [ ] map [ string ] interface { } { }
for _ , img := range storeSku . PictureList {
imgEbai , _ := api . EbaiAPI . PictureUpload ( img , nil )
if k == 0 {
photos = append ( photos , map [ string ] interface { } {
"is_master" : 1 ,
"url" : imgEbai ,
} )
} else {
photos = append ( photos , map [ string ] interface { } {
"is_master" : 0 ,
"url" : imgEbai ,
} )
}
}
params [ "photos" ] = photos
params [ "weight" ] = storeSku . SkuList [ 0 ] . Weight
params [ "weight" ] = storeSku . SkuList [ 0 ] . Weight
params [ "upc" ] = storeSku . SkuList [ 0 ] . Upc
params [ "name" ] = storeSku . Name
//params["cat3_id"] = storeSku.CateId
if storeSku . CategoryCode != "" {
params [ "category_id" ] = VendorCategoryIDMap [ storeSku . CategoryCode ]
} else {
params [ "category_id" ] = VendorCategoryIDMap [ storeSku . Name ]
}
if storeSku . PictureContents != "" {
params [ "desc" ] = storeSku . PictureContents
}
params [ "left_num" ] = storeSku . SkuList [ 0 ] . Stock
params [ "process_type" ] = 0 // 是否支持加工服务0-不支持/1-支持
//params["process_detail"] = storeSku.ProcessDetail
params [ "sale_price" ] = jxutils . StandardPrice2Int ( utils . Str2Float64 ( storeSku . SkuList [ 0 ] . Price ) )
if storeSku . IsSoldOut == 1 {
params [ "status" ] = 0
} else {
params [ "status" ] = 1
}
//params["minimum"] = storeSku.Minimum
//params["seven_days_no_reason"] = storeSku.SevenDaysNoReason
//if len(storeSku.SkuProperty) != model.NO {
// params["sku_property"] = storeSku.SkuProperty
//}
customSkuID := int64 ( storeSku . Ctime + k )
_ , err := toApi . SkuCreate ( ctx . GetTrackInfo ( ) , storeID , customSkuID , params )
if err != nil {
errList = append ( errList , err )
}
}
return errList
}
//#endregion
//#region 饿百同步到美团
func CopyEBaiToMt ( ctx * jxcontext . Context , fromStore , toStore * dao . StoreDetail , isAsync bool , offSet int ) ( hint string , errList [ ] string , err error ) {
var api = api . EbaiAPI
var toApi * mtwmapi . API
if toStore . VendorOrgCode == globals . Mtwm2Code {
toApi = mtwmapi . New ( beego . AppConfig . DefaultString ( "mtwmAppID2" , "" ) , beego . AppConfig . DefaultString ( "mtwmSecret2" , "" ) , beego . AppConfig . DefaultString ( "mtwmCallbackURL2" , "" ) , "" )
toApi . SetToken ( toStore . MtwmToken )
} else {
toApi = partner . CurAPIManager . GetAPI ( model . VendorIDMTWM , toStore . VendorOrgCode ) . ( * mtwmapi . API )
}
taskName := fmt . Sprintf ( "将美团平台门店[%s],分类和商品复制到[%s]" , fromStore . VendorStoreID , toStore . VendorStoreID )
config := tasksch . NewParallelConfig ( ) . SetParallelCount ( 1 ) . SetIsContinueWhenError ( false )
work := func ( task * tasksch . ParallelTask , batchItemList [ ] interface { } , params ... interface { } ) ( retVal interface { } , err error ) {
step := batchItemList [ 0 ] . ( int )
switch step {
case 1 :
//同步分类
fromCategoryList , err := api . ShopCategoryGet ( utils . Int2Str ( fromStore . ID ) )
if err != nil {
return nil , err
}
for _ , v := range fromCategoryList {
categoryErr := toApi . RetailCatUpdate ( toStore . VendorStoreID , v . Name , & mtwmapi . Param4UpdateCat {
CategoryCode : utils . Int64ToStr ( v . CategoryID ) ,
Sequence : v . Rank ,
} )
if categoryErr != nil {
globals . SugarLogger . Debugf ( "err := RetailCatUpdate : %v" , categoryErr )
}
if v . Children != nil && len ( v . Children ) != 0 {
for _ , c := range v . Children {
if err3 := toApi . RetailCatUpdate ( toStore . VendorStoreID , v . Name , & mtwmapi . Param4UpdateCat {
CategoryNameOrigin : v . Name ,
SecondaryCategoryCode : utils . Int64ToStr ( c . CategoryID ) ,
SecondaryCategoryName : c . Name ,
Sequence : c . Rank ,
} ) ; err3 != nil {
globals . SugarLogger . Debugf ( "err := RetailCatUpdate Children : %v" , err3 )
}
}
}
}
case 2 :
i := offSet
for {
// 同步商品
fromFoodList , err1 := api . SkuList ( utils . Int2Str ( fromStore . ID ) , & ebaiapi . SkuListParams {
Page : i ,
} )
if len ( fromFoodList . List ) == 0 || fromFoodList == nil {
return nil , fmt . Errorf ( "fromFoodList 为空 %s ,i:= %d" , utils . Format4Output ( err1 , false ) , i )
}
errDataList , err := BatchInitSkuEBai2Mt ( ctx , fromFoodList . List , toApi , toStore . VendorStoreID , i )
if err != nil {
globals . SugarLogger . Debugf ( "BatchInitData : %v" , err )
}
if len ( errDataList ) > model . NO {
globals . SugarLogger . Debugf ( "errListData %d:= %s" , i , utils . Format4Output ( errDataList , false ) )
for _ , v := range errDataList {
errList = append ( errList , fmt . Sprintf ( "%s,%s" , v . AppFoodCode , v . ErrorMsg ) )
}
}
globals . SugarLogger . Debugf ( "==========页数[%d],数据长度[%d]" , i , len ( fromFoodList . List ) )
if len ( fromFoodList . List ) < 100 {
break
}
i ++
}
}
return
}
task := tasksch . NewParallelTask ( taskName , config , ctx , work , [ ] int { 1 , 2 } )
tasksch . HandleTask ( task , nil , true ) . Run ( )
if ! isAsync {
_ , err = task . GetResult ( 0 )
hint = "1"
} else {
hint = task . ID
}
globals . SugarLogger . Debugf ( "======errrList := %s" , utils . Format4Output ( errList , false ) )
return hint , errList , err
}
func BatchInitSkuEBai2Mt ( ctx * jxcontext . Context , fromSku [ ] * ebaiapi . SkuInfo , toApi * mtwmapi . API , vendorStoreID string , offset int ) ( [ ] * mtwmapi . AppFoodResult , error ) {
errList := make ( [ ] * mtwmapi . AppFoodResult , 0 , 0 )
foodDataList := make ( [ ] map [ string ] interface { } , len ( fromSku ) )
isNeedUpdatePrice := true
for i , storeSku := range fromSku {
foodData := make ( map [ string ] interface { } )
foodDataList [ i ] = foodData
if storeSku . CustomSkuId != "" {
foodData [ mtwmapi . KeyAppFoodCode ] = storeSku . CustomSkuId
} else {
foodData [ mtwmapi . KeyAppFoodCode ] = storeSku . SkuId
}
skus := [ ] map [ string ] interface { } {
map [ string ] interface { } {
"sku_id" : foodData [ mtwmapi . KeyAppFoodCode ] ,
} ,
}
foodData [ "skus" ] = skus
foodData [ "name" ] = utils . LimitUTF8StringLen ( storeSku . Name , mtwmapi . MaxSkuNameCharCount )
//foodData["description"] = storeSku.Comment
if isNeedUpdatePrice {
foodData [ "price" ] = jxutils . IntPrice2Standard ( int64 ( storeSku . SalePrice ) )
}
if storeSku . Minimum != 0 {
foodData [ "min_order_count" ] = storeSku . Minimum
} else {
foodData [ "min_order_count" ] = 1
}
foodData [ "unit" ] = "份"
//todo 增加商品必填属性
attr := mtwm . SwitchAttr ( toApi , vendorStoreID , 0 , 0 , storeSku . Name )
if attr != "" {
foodData [ "common_attr_value" ] = attr
}
//if storeSku.SellPoint != "" {// 卖点
// foodData["sell_point"] = storeSku.SellPoint
//}
//if storeSku.SellPointTimes != "" {// 卖点展示期
// foodData["sell_point_available_times"] = storeSku.SellPointTimes
//}
if storeSku . CateId2 != 0 {
foodData [ "category_code" ] = storeSku . CateId2
} else {
foodData [ "category_name" ] = storeSku . CateName2
}
if storeSku . Status == "" {
foodData [ "is_sold_out" ] = 0
} else {
foodData [ "is_sold_out" ] = 1
}
photos := make ( [ ] string , 0 , len ( storeSku . Photos ) )
for _ , v := range storeSku . Photos {
photos = append ( photos , v . Url )
}
foodData [ "picture" ] = strings . Join ( photos , "," )
if storeSku . Rtf != "" {
foodData [ "picture_contents" ] = storeSku . Rtf
}
//if storeSku.QuaPictures != "" {
// foodData["qua_pictures"] = storeSku.QuaPictures
// foodData["qua_effective_date"] = storeSku.QuaEffectiveDate
// foodData["qua_approval_date"] = storeSku.QuaApprovalDate
//}
// 周期性可售时间段
//if storeSku.StatusSaleBegin != model.NO && storeSku.StatusSaleEnd != model.NO {
// saleStart := utils.Int2Str(int(storeSku.StatusSaleBegin))
// saleEnd := utils.Int2Str(int(storeSku.StatusSaleEnd))
// for {
// if len(saleStart) != 4 {
// saleStart = "0" + saleStart
// }
// if len(saleEnd) != 4 {
// saleEnd += "0" + saleEnd
// }
// if len(saleEnd) == 4 && len(saleStart) == 4 {
// break
// }
// }
// saleStart = fmt.Sprintf("%s:%s", saleStart[:2], saleStart[2:])
// saleEnd = fmt.Sprintf("%s:%s", saleEnd[:2], saleEnd[2:])
// availableTimes := fmt.Sprintf("%s-%s", saleStart, saleEnd)
// available, _ := json.Marshal(map[string]string{"monday": availableTimes, "tuesday": availableTimes, "wednesday": availableTimes, "thursday": availableTimes, "friday": availableTimes, "saturday": availableTimes, "sunday": availableTimes})
// foodData["available_times"] = string(available)
//}
//foodData["sequence"] = storeSku.GetSeq()
if tempCateId , err := toApi . RetailRecommendTag ( storeSku . Name , vendorStoreID , 0 , mtwmapi . TypeCategory ) ; err == nil {
foodData [ "tag_id" ] = int64 ( tempCateId . TagID )
}
//skus[0]["spec"] = jxutils.ComposeSkuSpec(storeSku.SpecQuality, storeSku.SpecUnit)
skus [ 0 ] [ "price" ] = utils . Float64ToStr ( jxutils . IntPrice2Standard ( int64 ( storeSku . SalePrice ) ) )
skus [ 0 ] [ "stock" ] = utils . Int2Str ( storeSku . LeftNum )
skus [ 0 ] [ "upc" ] = storeSku . Upc
if storeSku . ShelfNumber != "" {
skus [ 0 ] [ "location_code" ] = storeSku . ShelfNumber
}
//skus[0]["ladder_box_num"] = "0"
//skus[0]["ladder_box_price"] = "0"
// 下面这个两个和上面有点重复,但是上面两个在更新的时候美团不识别,不知道创建的时候会不会覆盖一下吧(更新只能用下面这个)
skus [ 0 ] [ "box_num" ] = "0"
skus [ 0 ] [ "box_price" ] = "0"
if foodData [ "tag_id" ] != nil {
skus [ 0 ] [ "weight" ] = storeSku . Weight // weight字段仅限服饰鞋帽、美妆、日用品、母婴、生鲜果蔬、生活超市下的便利店/超市门店品类的商家使用
}
}
count := len ( foodDataList ) / 10
if len ( foodDataList ) % 10 != 0 {
count += 1
}
for i := 0 ; i < count ; i ++ {
if i == count - 1 {
failedFoodList , _ := toApi . RetailBatchInitData ( ctx . GetTrackInfo ( ) , vendorStoreID , foodDataList [ i * 10 : ] )
if len ( failedFoodList ) != 0 {
globals . SugarLogger . Debugf ( "failedFoodList := %s" , utils . Format4Output ( failedFoodList , false ) )
errList = append ( errList , failedFoodList ... )
}
} else {
failedFoodList , _ := toApi . RetailBatchInitData ( ctx . GetTrackInfo ( ) , vendorStoreID , foodDataList [ i * 10 : ( i + 1 ) * 10 ] )
if len ( failedFoodList ) != 0 {
globals . SugarLogger . Debugf ( "failedFoodList := %s" , utils . Format4Output ( failedFoodList , false ) )
errList = append ( errList , failedFoodList ... )
}
}
}
return errList , nil
}
//#endregion
//#endregion
////#region 同步活动
//
//func CopyMtActToMt(ctx *jxcontext.Context, fromStore, toStore *dao.StoreDetail) {