diff --git a/business/jxstore/cms/store_sku.go b/business/jxstore/cms/store_sku.go index 5ce546a38..1b4419837 100644 --- a/business/jxstore/cms/store_sku.go +++ b/business/jxstore/cms/store_sku.go @@ -573,6 +573,8 @@ func updateStoresSkusWithoutSync(ctx *jxcontext.Context, storeIDs []int, skuBind model.FieldJdSyncStatus: model.SyncFlagDeletedMask, model.FieldElmSyncStatus: model.SyncFlagDeletedMask, model.FieldEbaiSyncStatus: model.SyncFlagDeletedMask, + model.FieldMtwmSyncStatus: model.SyncFlagDeletedMask, + model.FieldWscSyncStatus: model.SyncFlagDeletedMask, }, userName, nil); err != nil { dao.Rollback(db) return nil, err @@ -1250,6 +1252,8 @@ func setStoreSkuBindStatus(skuBind *model.StoreSkuBind, status int8) { skuBind.JdSyncStatus |= status skuBind.ElmSyncStatus |= status skuBind.EbaiSyncStatus |= status + skuBind.MtwmSyncStatus |= status + skuBind.WscSyncStatus |= status } func checkStoreExisting(db *dao.DaoDB, storeID int) (err error) { diff --git a/business/jxstore/cms/sync.go b/business/jxstore/cms/sync.go index 986666290..b2f041384 100644 --- a/business/jxstore/cms/sync.go +++ b/business/jxstore/cms/sync.go @@ -58,6 +58,7 @@ func Init() { model.VendorIDELM: api.ElmAPI, model.VendorIDEBAI: api.EbaiAPI, model.VendorIDMTWM: api.MtwmAPI, + model.VendorIDWSC: api.WeimobAPI, } CurVendorSync.PurchaseHandlers = make(map[int]partner.IPurchasePlatformHandler) for k, v := range partner.PurchasePlatformHandlers { diff --git a/business/jxstore/initdata/initdata.go b/business/jxstore/initdata/initdata.go index 8ab98a7a0..e535a19ff 100644 --- a/business/jxstore/initdata/initdata.go +++ b/business/jxstore/initdata/initdata.go @@ -167,13 +167,12 @@ func InitSkuName(ctx *jxcontext.Context, isForce, isAsync, isContinueWhenError b return hint, err } -func InitVendorCategory(ctx *jxcontext.Context) (num int64, err error) { - if handler, ok := partner.PurchasePlatformHandlers[model.VendorIDMTWM].(*mtwm.PurchaseHandler); ok { +func InitVendorCategory(ctx *jxcontext.Context, vendorID int) (num int64, err error) { + if handler, ok := partner.PurchasePlatformHandlers[vendorID].(*mtwm.PurchaseHandler); ok { cats, err2 := handler.GetVendorCategories() if err2 != nil { return num, err2 } - db := dao.GetDB() dao.Begin(db) defer dao.Rollback(db) @@ -182,7 +181,7 @@ func InitVendorCategory(ctx *jxcontext.Context) (num int64, err error) { FROM sku_vendor_category WHERE vendor_id = ? ` - if _, err = dao.ExecuteSQL(db, sql, model.VendorIDMTWM); err != nil { + if _, err = dao.ExecuteSQL(db, sql, vendorID); err != nil { return num, err } for _, cat := range cats { @@ -445,3 +444,28 @@ func Change2JDSPU4Store(ctx *jxcontext.Context, storeIDs []int, step int, isAsyn hint, err = cms.CurVendorSync.SyncStoresSkus(ctx, db, []int{model.VendorIDJD}, storeIDs, skuIDs, isAsync, isContinueWhenError) return hint, err } + +func UploadWeimobImg4SkuName(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) { + db := dao.GetDB() + skuNameList, err := dao.GetSkuNames(db) + if err != nil { + return "", err + } + rootTask := tasksch.NewParallelTask("UploadWeimobImg4SkuName", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError).SetParallelCount(5), ctx.GetUserName(), func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + skuName := batchItemList[0].(*model.SkuName) + if skuName.Img != "" && skuName.ImgWeimob == "" { + if skuName.ImgWeimob, err = api.WeimobAPI.UploadImgByURL(skuName.Img, ""); err == nil { + _, err = dao.UpdateEntity(db, skuName) + } + } + return nil, err + }, skuNameList) + tasksch.ManageTask(rootTask).Run() + + if !isAsync { + _, err = rootTask.GetResult(0) + } else { + hint = rootTask.ID + } + return hint, err +} diff --git a/business/model/const.go b/business/model/const.go index a1dfa107e..2790a98af 100644 --- a/business/model/const.go +++ b/business/model/const.go @@ -8,7 +8,8 @@ const ( VendorIDMTWM = 1 VendorIDELM = 2 VendorIDEBAI = 3 - VendorIDPurchaseEnd = 3 + VendorIDWSC = 11 // 微盟微商城 + VendorIDPurchaseEnd = 11 VendorIDDeliveryBegin = 101 VendorIDDada = 101 @@ -23,6 +24,8 @@ var ( VendorIDMTWM: "Mtwm", VendorIDELM: "Elm", VendorIDEBAI: "Ebai", + VendorIDWSC: "Wsc", + VendorIDDada: "Dada", VendorIDMTPS: "Mtps", } @@ -31,6 +34,8 @@ var ( VendorIDMTWM: "美团外卖", VendorIDELM: "饿了么", VendorIDEBAI: "饿百新零售", + VendorIDWSC: "微盟微商城", + VendorIDDada: "达达众包", VendorIDMTPS: "美团配送", } @@ -165,3 +170,13 @@ const ( OrderDeliveryFlagMaskScheduleDisabled = 1 // 禁止三方配送调度 OrderDeliveryFlagMaskPurcahseDisabled = 2 // 购物平台已不配送(一般为门店配送类型本身为自配送,或已经转自配送) ) + +func IsPurchaseVendorExist(vendorID int) bool { + _, ok := VendorNames[vendorID] + return ok && vendorID >= VendorIDPurchaseBegin && vendorID <= VendorIDPurchaseEnd +} + +func IsDeliveryVendorExist(vendorID int) bool { + _, ok := VendorNames[vendorID] + return ok && vendorID >= VendorIDDeliveryBegin && vendorID <= VendorIDDeliveryEnd +} diff --git a/business/model/dao/dao_bz.go b/business/model/dao/dao_bz.go index 15fe13c48..c62cda227 100644 --- a/business/model/dao/dao_bz.go +++ b/business/model/dao/dao_bz.go @@ -112,8 +112,10 @@ func DeleteEntityLogically(db *DaoDB, item interface{}, kvs map[string]interface func AddStoreCategoryMap(db *DaoDB, storeID, categoryID int, vendorID int, vendorCategoryID string, status int8, userName string) (err error) { storeCat := &model.StoreSkuCategoryMap{ - StoreID: storeID, - CategoryID: categoryID, + StoreID: storeID, + CategoryID: categoryID, + MtwmSyncStatus: model.SyncFlagNewMask, + WscSyncStatus: model.SyncFlagNewMask, } storeCat.DeletedAt = utils.DefaultTimeValue if err = GetEntity(db, storeCat, model.FieldStoreID, model.FieldCategoryID, model.FieldDeletedAt); err != nil && err != orm.ErrNoRows { diff --git a/business/model/dao/sku.go b/business/model/dao/sku.go index 1dbc74652..815d5b7bb 100644 --- a/business/model/dao/sku.go +++ b/business/model/dao/sku.go @@ -1,6 +1,7 @@ package dao import ( + "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/model" ) @@ -50,3 +51,18 @@ func GetSkuNameByHashCode(db *DaoDB, hashCode string) (skuName *model.SkuName, e } return nil, err } + +func GetSkuNames(db *DaoDB) (skuNameList []*model.SkuName, err error) { + sql := ` + SELECT * + FROM sku_name + WHERE deleted_at = ? + ` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + } + if err = GetRows(db, &skuNameList, sql, sqlParams...); err == nil { + return skuNameList, nil + } + return nil, err +} diff --git a/business/model/dao/store_sku.go b/business/model/dao/store_sku.go index 724cd0189..56522d078 100644 --- a/business/model/dao/store_sku.go +++ b/business/model/dao/store_sku.go @@ -38,8 +38,9 @@ type StoreSkuSyncInfo struct { StoreSkuStatus int SkuSyncStatus int8 model.Sku - VendorSkuID int64 `orm:"column(vendor_sku_id)"` + VendorSkuID string `orm:"column(vendor_sku_id)"` Prefix string + NameID int `orm:"column(name_id)"` Name string Unit string Img string @@ -119,10 +120,14 @@ func GetStoreSkus(db *DaoDB, vendorID, storeID int, skuIDs []int) (skus []*Store if model.MultiStoresVendorMap[vendorID] == 1 { // 多店模式平台 tableName = "t2" } + imgField := "img" + if vendorID == model.VendorIDWSC { + imgField = "img_weimob" + } sql := ` SELECT t1.id bind_id, t1.price, t1.unit_price, t1.status store_sku_status, %s.%s_id vendor_sku_id, t1.%s_sync_status sku_sync_status, t2.*, - t3.prefix, t3.name, t3.unit, t3.img, t3.upc, + t3.id name_id, t3.prefix, t3.name, t3.unit, t3.%s img, t3.upc, t4.%s_category_id vendor_vendor_cat_id, t5.%s_sync_status cat_sync_status, t5.%s_id vendor_cat_id, t5sku.%s_sync_status sku_cat_sync_status, t5sku.%s_id sku_vendor_cat_id @@ -144,9 +149,10 @@ func GetStoreSkus(db *DaoDB, vendorID, storeID int, skuIDs []int) (skus []*Store sqlParams = append(sqlParams, skuIDs) } fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID]) - sql = fmt.Sprintf(sql, tableName, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix) + sql = fmt.Sprintf(sql, tableName, fieldPrefix, fieldPrefix, imgField, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix) // globals.SugarLogger.Debug(sql) if err = GetRows(db, &skus, sql, sqlParams...); err != nil { + globals.SugarLogger.Debug("fuck") return nil, err } return skus, err @@ -159,7 +165,7 @@ func GetFullStoreSkus(db *DaoDB, vendorID, storeID int) (skus []*StoreSkuSyncInf sql := ` SELECT t1.id bind_id, t1.price, t1.unit_price, t1.status store_sku_status, t2.%s_id vendor_sku_id, t1.%s_sync_status sku_sync_status, t2.*, - t3.prefix, t3.name, t3.unit, t3.img, + t3.id name_id, t3.prefix, t3.name, t3.unit, t3.img, t4.%s_category_id vendor_vendor_cat_id, t4.%s_sync_status cat_sync_status, t4.%s_id vendor_cat_id, t5sku.%s_sync_status sku_cat_sync_status, t5sku.%s_id sku_vendor_cat_id diff --git a/business/model/model.go b/business/model/model.go index aeb7a6149..b3cff3284 100644 --- a/business/model/model.go +++ b/business/model/model.go @@ -17,6 +17,7 @@ const ( FieldElmSyncStatus = "ElmSyncStatus" FieldEbaiSyncStatus = "EbaiSyncStatus" FieldMtwmSyncStatus = "MtwmSyncStatus" + FieldWscSyncStatus = "WscSyncStatus" FieldVendorID = "VendorID" FieldStoreID = "StoreID" @@ -30,6 +31,7 @@ const ( FieldElmID = "ElmID" FieldEbaiID = "EbaiID" FieldMtwmID = "MtwmID" + FieldWscID = "WscID" FieldSkuID = "SkuID" FieldLevel = "Level" diff --git a/business/model/sku.go b/business/model/sku.go index 5613322f6..c61620e3c 100644 --- a/business/model/sku.go +++ b/business/model/sku.go @@ -135,6 +135,7 @@ type SkuCategory struct { ElmCategoryID int64 `orm:"column(elm_category_id)" json:"elmCategoryID"` // 这个是指对应的饿了么商品类别 EbaiCategoryID int64 `orm:"column(ebai_category_id)" json:"ebaiCategoryID"` // 这个是指对应的饿百商品类别 MtwmCategoryID int64 `orm:"column(mtwm_category_id)" json:"mtwmCategoryID"` // 这个是指对应的美团外卖商品类别 + WscCategoryID int64 `orm:"column(wsc_category_id)" json:"wscCategoryID"` // 这个是指对应的美团外卖商品类别 JdID int64 `orm:"column(jd_id);null" json:"jdID"` // 这个是指商家自己的商品类别在京东平台上的ID JdSyncStatus int8 `orm:"default(2)" json:"jdSyncStatus"` @@ -162,13 +163,15 @@ type SkuName struct { SpecUnit string `orm:"size(8)" json:"-"` // 为份必然为克,这个主要作用只是用于确保SkuName的唯一性 Price int `json:"price"` // 单位为分,标准价,不为份的就为实际标准价,为份的为每市斤价,实际还要乘质量。todo 为份的确定必须有质量 Img string `orm:"size(255)" json:"img"` + ImgWeimob string `orm:"size(255)" json:"imgWeimob"` // 微盟图片地址 ImgHashCode string `orm:"size(255);index" json:"img_hash_code"` ElmImgHashCode string `orm:"size(255)" json:"-"` // 长度255的原因是从京东初始化数据时临时需要 Upc string `orm:"size(20)"` Status int `orm:"default(1)" json:"status"` // skuname状态,取值同sku.Status IsSpu int8 `orm:"column(is_spu)" json:"isSpu"` // 用于指明是否SKUNAME当成SPU - JdID int64 `orm:"column(jd_id);null;index" json:"jdID"` - JdSyncStatus int8 `orm:"default(2)" json:"jdSyncStatus"` + + JdID int64 `orm:"column(jd_id);null;index" json:"jdID"` + JdSyncStatus int8 `orm:"default(2)" json:"jdSyncStatus"` LinkID int `orm:"column(link_id);null;index" json:"linkID"` } diff --git a/business/model/store_sku.go b/business/model/store_sku.go index a5f9f2eb6..18ce9c9e7 100644 --- a/business/model/store_sku.go +++ b/business/model/store_sku.go @@ -44,10 +44,12 @@ type StoreSkuCategoryMap struct { ElmID int64 `orm:"column(elm_id);index"` EbaiID int64 `orm:"column(ebai_id);index"` MtwmID string `orm:"column(mtwm_id);index;size(16)"` // 美团外卖没有ID,保存名字 + WscID int64 `orm:"column(wsc_id);index"` ElmSyncStatus int8 `orm:"default(2)"` EbaiSyncStatus int8 `orm:"default(2)"` MtwmSyncStatus int8 `orm:"default(2)"` + WscSyncStatus int8 `orm:"default(2)"` } func (*StoreSkuCategoryMap) TableUnique() [][]string { @@ -66,14 +68,17 @@ type StoreSkuBind struct { UnitPrice int // 这个是一斤的门店商品价,放在这里的原因是避免额外增加一张store sku_name表,逻辑上要保证同一SKU NAME中的所有SKU这个字段的数据一致 Status int - ElmID int64 `orm:"column(elm_id);index"` - EbaiID int64 `orm:"column(ebai_id);index"` - MtwmID int64 `orm:"column(mtwm_id)"` // 这个也不是必须的,只是为了DAO取数据语句一致 + ElmID int64 `orm:"column(elm_id);index"` + EbaiID int64 `orm:"column(ebai_id);index"` + MtwmID int64 `orm:"column(mtwm_id)"` // 这个也不是必须的,只是为了DAO取数据语句一致 + WscID string `orm:"column(wsc_id);size(64);index"` - JdSyncStatus int8 - ElmSyncStatus int8 - EbaiSyncStatus int8 - MtwmSyncStatus int8 + JdSyncStatus int8 `orm:"default(2)"` + + ElmSyncStatus int8 `orm:"default(2)"` + EbaiSyncStatus int8 `orm:"default(2)"` + MtwmSyncStatus int8 `orm:"default(2)"` + WscSyncStatus int8 `orm:"default(2)"` } func (*StoreSkuBind) TableUnique() [][]string { diff --git a/business/partner/partner.go b/business/partner/partner.go index 118b7db93..e2263319a 100644 --- a/business/partner/partner.go +++ b/business/partner/partner.go @@ -151,7 +151,7 @@ func Init(curOrderManager IOrderManager) { func RegisterPurchasePlatform(handler IPurchasePlatformHandler) { vendorID := handler.GetVendorID() - if !(vendorID >= model.VendorIDPurchaseBegin && vendorID <= model.VendorIDPurchaseEnd) { + if !(model.IsPurchaseVendorExist(vendorID)) { panic(fmt.Sprintf("purchase vendor:%d is illegal", vendorID)) } if _, ok := PurchasePlatformHandlers[vendorID]; ok { @@ -162,7 +162,7 @@ func RegisterPurchasePlatform(handler IPurchasePlatformHandler) { func RegisterDeliveryPlatform(handler IDeliveryPlatformHandler, isUse4CreateWaybill bool) { vendorID := handler.GetVendorID() - if !(vendorID >= model.VendorIDDeliveryBegin && vendorID <= model.VendorIDDeliveryEnd) { + if !(model.IsDeliveryVendorExist(vendorID)) { panic(fmt.Sprintf("delivery vendor:%d is illegal", vendorID)) } if _, ok := DeliveryPlatformHandlers[vendorID]; ok { diff --git a/business/partner/purchase/mtwm/store_sku.go b/business/partner/purchase/mtwm/store_sku.go index 509bedac7..72cef871a 100644 --- a/business/partner/purchase/mtwm/store_sku.go +++ b/business/partner/purchase/mtwm/store_sku.go @@ -157,6 +157,7 @@ func (p *PurchaseHandler) SyncLocalStoreCategory(ctx *jxcontext.Context, db *dao MtwmSyncStatus: mtwmSyncStatus, EbaiSyncStatus: model.SyncFlagNewMask, ElmSyncStatus: model.SyncFlagNewMask, + WscSyncStatus: model.SyncFlagNewMask, } num++ dao.WrapAddIDCULDEntity(catMap, ctx.GetUserName()) diff --git a/business/partner/purchase/weimob/wsc/order.go b/business/partner/purchase/weimob/wsc/order.go new file mode 100644 index 000000000..8e7948f67 --- /dev/null +++ b/business/partner/purchase/weimob/wsc/order.go @@ -0,0 +1,45 @@ +package wsc + +import ( + "time" + + "git.rosy.net.cn/jx-callback/business/model" +) + +func (p *PurchaseHandler) GetStatusFromVendorStatus(vendorStatus string) int { + return 0 +} +func (p *PurchaseHandler) GetOrder(vendorOrderID string) (order *model.GoodsOrder, err error) { + return order, err +} + +func (p *PurchaseHandler) GetStatusActionTimeout(statusType, status int) time.Duration { + return 0 +} + +func (p *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) { + return err +} +func (p *PurchaseHandler) PickupGoods(order *model.GoodsOrder, userName string) (err error) { + return err +} + +// 将订单从购物平台配送转为自送 +func (p *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) { + return err +} + +// 将订单从购物平台配送转为自送后又送达 +func (p *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) { + return err +} + +// 完全自送的门店表示开始配送 +func (p *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) { + return err +} + +// 完全自送的门店表示配送完成 +func (p *PurchaseHandler) SelfDeliverDelievered(order *model.GoodsOrder, userName string) (err error) { + return err +} diff --git a/business/partner/purchase/weimob/wsc/store.go b/business/partner/purchase/weimob/wsc/store.go new file mode 100644 index 000000000..7950ad2bb --- /dev/null +++ b/business/partner/purchase/weimob/wsc/store.go @@ -0,0 +1,22 @@ +package wsc + +import ( + "errors" + + "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" +) + +func (p *PurchaseHandler) ReadStore(vendorStoreID string) (*model.Store, error) { + return nil, errors.New("微盟微商城还没实现") +} + +func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) error { + return nil +} + +func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) { + return hint, err +} diff --git a/business/partner/purchase/weimob/wsc/store_sku.go b/business/partner/purchase/weimob/wsc/store_sku.go new file mode 100644 index 000000000..515ac21e2 --- /dev/null +++ b/business/partner/purchase/weimob/wsc/store_sku.go @@ -0,0 +1,268 @@ +package wsc + +import ( + "errors" + "fmt" + "strings" + + "git.rosy.net.cn/baseapi/platformapi/weimobapi" + "git.rosy.net.cn/baseapi/utils" + "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/globals" + "git.rosy.net.cn/jx-callback/globals/api" +) + +const ( + DefFreightTemplateId = 6537248 + DefDeliveryTypeId = 177445 + DefVendorCategoryId = 35 + DefCatImg = "https://image-c.weimobwmc.com/openruntime/249b77ced5da4736a56641ebcf4875ec.png" +) + +func (p *PurchaseHandler) SyncStoreCategory(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync bool) (hint string, err error) { + userName := ctx.GetUserName() + strStoreID := utils.Int2Str(storeID) + num := 0 + db := dao.GetDB() + rootTask := tasksch.NewSeqTask("微盟微商城SyncStoreCategory step1", userName, func(rootTask *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { + level := step + 1 + catList, err := dao.GetStoreCategories(db, model.VendorIDWSC, storeID, level) + // globals.SugarLogger.Debug(utils.Format4Output(catList, false)) + if len(catList) > 0 { + num += len(catList) + task := tasksch.NewParallelTask(fmt.Sprintf("微盟微商城SyncStoreCategory step2, level=%d", level), nil, userName, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + updateFields := []string{dao.GetSyncStatusStructField(model.VendorNames[model.VendorIDWSC])} + catInfo := batchItemList[0].(*dao.StoreCatSyncInfo) + if globals.EnableStoreWrite && globals.EnableWscStoreWrite { + if catInfo.WscSyncStatus&model.SyncFlagDeletedMask != 0 { // 删除 + globals.SugarLogger.Debugf("UpdateClassify strStoreID:%s, WscID:%d", strStoreID, catInfo.WscID) + err = api.WeimobAPI.UpdateClassify(catInfo.WscID, catInfo.CatName+"del", "") + } else if catInfo.WscSyncStatus&(model.SyncFlagNewMask|model.SyncFlagModifiedMask) != 0 { // 新增 + catImg := "" + if level == 2 { + catImg = DefCatImg + } + if catInfo.WscID, err = api.WeimobAPI.AddClassify(catInfo.CatName, utils.Str2Int64(catInfo.ParentVendorCatID), catImg); err == nil { + updateFields = append(updateFields, dao.GetVendorThingIDStructField(model.VendorNames[model.VendorIDWSC])) + } + } else if catInfo.WscSyncStatus&(model.SyncFlagModifiedMask|model.SyncFlagModifiedMask) != 0 { // 修改 + err = api.WeimobAPI.UpdateClassify(catInfo.WscID, catInfo.CatName, "") + } + } + if err == nil { + db2 := dao.GetDB() + catInfo.WscSyncStatus = 0 + _, err = dao.UpdateEntity(db2, &catInfo.StoreSkuCategoryMap, updateFields...) + } + return nil, err + }, catList) + rootTask.AddChild(task).Run() + _, err = task.GetResult(0) + } + return nil, err + }, 2) + tasksch.AddChild(parentTask, rootTask).Run() + if !isAsync { + hint = utils.Int2Str(num) + _, err = rootTask.GetResult(0) + } else { + hint = rootTask.ID + } + return "", nil +} + +// 此函数根据门店商品信息重建分类信息 +// 远程有,本地无, --> 删除远程 +// 远程有,本地有,映射无, --> 添加关联 +// 远程有,本地有,映射有, --> 不处理 +// 远程无,本地有,映射无, --> 添加本地 +// 远程无,本地有,映射有, --> 同步标记改为新增 +// hint,如果是异步,返回的是任务ID,如果是同步,返回是本次需要同步的目录数 +func (p *PurchaseHandler) SyncLocalStoreCategory(ctx *jxcontext.Context, db *dao.DaoDB, storeID int, isAsync bool) (hint string, err error) { + if db == nil { + db = dao.GetDB() + } + catMap := make([]map[string]*dao.SkuStoreCatInfo, 2) + for i := 0; i < 2; i++ { + catMap[i] = make(map[string]*dao.SkuStoreCatInfo) + localCats, err := dao.GetSkusCategories(db, model.VendorIDWSC, storeID, nil, i+1) + // globals.SugarLogger.Debug(utils.Format4Output(localCats, false)) + if err != nil { + return "", err + } + for _, cat := range localCats { + catMap[i][cat.ParentCatName+"/"+cat.Name] = cat + } + } + + dao.Begin(db) + defer func() { + dao.Rollback(db) + }() + num := 0 + for i := 0; i < 2; i++ { + for _, v := range catMap[i] { + if v.MapID == -1 || v.MapID == 0 { // 本地缺失 + wscSyncStatus := int8(model.SyncFlagNewMask) + if v.MapID == -1 { // 远程有同名的,只是简单增加一条本地记录关联 + wscSyncStatus = 0 + } + catMap := &model.StoreSkuCategoryMap{ + StoreID: storeID, + CategoryID: v.ID, + WscID: utils.Str2Int64(v.VendorCatID), + WscSyncStatus: wscSyncStatus, + MtwmSyncStatus: model.SyncFlagNewMask, + EbaiSyncStatus: model.SyncFlagNewMask, + ElmSyncStatus: model.SyncFlagNewMask, + } + num++ + dao.WrapAddIDCULDEntity(catMap, ctx.GetUserName()) + if err = dao.CreateEntity(db, catMap); err != nil { + return "", err + } + } else { + if (v.VendorCatID == "0" || v.VendorCatID == "") && ((v.CatSyncStatus & model.SyncFlagNewMask) == 0) { + catMap := &model.StoreSkuCategoryMap{} + catMap.ID = v.MapID + if _, err = dao.UpdateEntityLogically(db, catMap, map[string]interface{}{ + model.FieldWscSyncStatus: model.SyncFlagNewMask, + }, ctx.GetUserName(), nil); err != nil { + return "", err + } + } + } + } + } + dao.Commit(db) + return utils.Int2Str(num), err +} + +// hint,如果是异步,返回的是任务ID,如果是同步,返回是本次需要同步的目录数 +func (p *PurchaseHandler) SyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { + db := dao.GetDB() + for i := 0; i < 3; i++ { // 最多重试三次 + if hint, err = p.SyncLocalStoreCategory(ctx, db, storeID, false); err != nil { + return "", err + } + if hint != "0" { + if hint, err = p.SyncStoreCategory(ctx, parentTask, storeID, false); err != nil { + return "", err + } + } + if hint == "0" { + break + } + } + if hint != "0" { + return "", errors.New("同步门店商品所需目录失败") + } + storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDWSC) + if err != nil { + return "", err + } + skus, err := dao.GetStoreSkus(db, model.VendorIDWSC, storeID, skuIDs) + if err != nil { + return "", err + } + globals.SugarLogger.Debug(utils.Format4Output(skus, false)) + rootTask := tasksch.NewParallelTask("微盟微商城SyncStoreSkus", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx.GetUserName(), func(rootTask *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + v := batchItemList[0] + skuItem := v.(*dao.StoreSkuSyncInfo) + updateFields := []string{model.FieldWscSyncStatus} + storeSkuBind := &model.StoreSkuBind{} + storeSkuBind.ID = skuItem.BindID + if skuItem.SkuSyncStatus&model.SyncFlagDeletedMask != 0 { + goodsID, _ := SplitGoodsAndSkuIDFromJXVendorSkuID(skuItem.VendorSkuID) + if err = api.WeimobAPI.UpdateGoodsShelfStatus([]int64{goodsID}, false); err == nil { + err = api.WeimobAPI.UpdateGoodsTitle(goodsID, skuItem.Name+"del") + } + } else if skuItem.SkuSyncStatus&(model.SyncFlagModifiedMask|model.SyncFlagNewMask) != 0 { + outerGoodsCode := utils.Int2Str(skuItem.NameID) + title := jxutils.ComposeSkuName(skuItem.Prefix, skuItem.Name, skuItem.Comment, skuItem.Unit, skuItem.SpecQuality, skuItem.SpecUnit, 30) + isPutAway := jxutils.MergeSkuStatus(skuItem.Status, skuItem.StoreSkuStatus) == model.SkuStatusNormal + categoryId := skuItem.VendorVendorCatID + if categoryId == 0 { + categoryId = DefVendorCategoryId + } + classifyIdList := []int64{utils.Str2Int64(skuItem.VendorCatID)} + if skuItem.SkuVendorCatID != "" { + if int64Value := utils.Str2Int64(skuItem.SkuVendorCatID); int64Value > 0 { + classifyIdList = append(classifyIdList, int64Value) + } + } + b2cGoods := &weimobapi.PendingSaveB2CGoodsVo{ + FreightTemplateId: DefFreightTemplateId, + DeliveryTypeIdList: []int64{DefDeliveryTypeId}, + B2cGoodsType: weimobapi.GoodsTypeNormal, + } + skuList := []map[string]interface{}{ + map[string]interface{}{ + weimobapi.KeyOuterSkuCode: utils.Int2Str(skuItem.ID), + weimobapi.KeyImageURL: skuItem.Img, + weimobapi.KeySalePrice: jxutils.IntPrice2Standard(int64(jxutils.CaculateSkuVendorPrice(int(skuItem.Price), int(storeDetail.PricePercentage)))), + weimobapi.KeyEditStockNum: model.MaxStoreSkuStockQty, + weimobapi.KeyB2cSku: &weimobapi.PendingSaveB2CSkuVo{ + Weight: jxutils.IntWeight2Float(skuItem.Weight), + }, + }, + } + if globals.EnableStoreWrite && globals.EnableWscStoreWrite { + if skuItem.SkuSyncStatus&model.SyncFlagNewMask != 0 { + goodsID, skuMap, err2 := api.WeimobAPI.AddGoods(outerGoodsCode, title, false, []string{skuItem.Img}, skuItem.Comment, isPutAway, 0, categoryId, classifyIdList, b2cGoods, skuList, nil) + if err = err2; err == nil { + storeSkuBind.WscID = ComposeJXVendorSkuIDFromGoodsAndSkuID(goodsID, skuMap[utils.Int2Str(skuItem.ID)]) + updateFields = append(updateFields, model.FieldWscID) + } + } else { + goodsID, _ := SplitGoodsAndSkuIDFromJXVendorSkuID(skuItem.VendorSkuID) + _, _, err = api.WeimobAPI.UpdateGoods(goodsID, title, false, []string{skuItem.Img}, skuItem.Comment, isPutAway, 0, categoryId, classifyIdList, b2cGoods, skuList, nil) + } + } + } + if err == nil { + _, err = dao.UpdateEntity(nil, storeSkuBind, updateFields...) + } + return nil, err + }, skus) + if parentTask != nil { + parentTask.AddChild(rootTask) + } + rootTask.Run() + if !isAsync { + _, err = rootTask.GetResult(0) + hint = utils.Int2Str(len(skus)) + } else { + hint = rootTask.ID + } + return hint, err +} + +func (p *PurchaseHandler) RefreshStoresAllSkusID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool, storeIDs []int) (hint string, err error) { + return hint, err +} + +func (p *PurchaseHandler) FullSyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync, isContinueWhenError bool) (hint string, err error) { + return hint, err +} + +func (p *PurchaseHandler) DeleteRemoteStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync, isContinueWhenError bool) (hint string, err error) { + return hint, err +} + +func SplitGoodsAndSkuIDFromJXVendorSkuID(vendorSkuID string) (goodsID, skuID int64) { + list := strings.Split(vendorSkuID, ",") + if len(list) == 2 { + goodsID = utils.Str2Int64(list[0]) + skuID = utils.Str2Int64(list[1]) + } + return goodsID, skuID +} + +func ComposeJXVendorSkuIDFromGoodsAndSkuID(goodsID, skuID int64) (vendorSkuID string) { + return utils.Int64ToStr(goodsID) + "," + utils.Int64ToStr(skuID) +} diff --git a/business/partner/purchase/weimob/wsc/store_sku_test.go b/business/partner/purchase/weimob/wsc/store_sku_test.go new file mode 100644 index 000000000..ad0c92910 --- /dev/null +++ b/business/partner/purchase/weimob/wsc/store_sku_test.go @@ -0,0 +1,31 @@ +package wsc + +import ( + "testing" + + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" +) + +func TestSyncLocalStoreCategory(t *testing.T) { + hint, err := new(PurchaseHandler).SyncLocalStoreCategory(jxcontext.AdminCtx, nil, 100077, false) + if err != nil { + t.Fatal(err) + } + t.Log(hint) +} + +func TestSyncStoreCategory(t *testing.T) { + hint, err := new(PurchaseHandler).SyncStoreCategory(jxcontext.AdminCtx, nil, 100077, false) + if err != nil { + t.Fatal(err) + } + t.Log(hint) +} + +func TestSyncStoreSkus(t *testing.T) { + hint, err := new(PurchaseHandler).SyncStoreSkus(jxcontext.AdminCtx, nil, 100077, nil, false, true) + if err != nil { + t.Fatal(err) + } + t.Log(hint) +} diff --git a/business/partner/purchase/weimob/wsc/wsc.go b/business/partner/purchase/weimob/wsc/wsc.go new file mode 100644 index 000000000..517e8e1c0 --- /dev/null +++ b/business/partner/purchase/weimob/wsc/wsc.go @@ -0,0 +1,59 @@ +package wsc + +import ( + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/partner" + "git.rosy.net.cn/jx-callback/globals/api" +) + +var ( + curPurchaseHandler *PurchaseHandler +) + +type PurchaseHandler struct { + partner.BasePurchasePlatform +} + +func init() { + curPurchaseHandler = new(PurchaseHandler) + partner.RegisterPurchasePlatform(curPurchaseHandler) +} + +func (c *PurchaseHandler) GetVendorID() int { + return model.VendorIDWSC +} + +func (p *PurchaseHandler) GetVendorCategories() (vendorCats []*model.SkuVendorCategory, err error) { + rootCats, err := api.WeimobAPI.QueryCategoryTree() + catList := rootCats + if err != nil { + return nil, err + } + for _, v := range rootCats { + cats, err := api.WeimobAPI.QueryChildrenCategory(v.CategoryID) + if err != nil { + return nil, err + } + catList = append(catList, cats...) + } + vendorCats = make([]*model.SkuVendorCategory, len(catList)) + for k, v := range catList { + vendorCats[k] = &model.SkuVendorCategory{ + VendorCategoryID: vendorCategoryID2String(v.CategoryID), + VendorID: model.VendorIDWSC, + Name: v.Title, + IsLeaf: int8(v.Level - 1), + Level: v.Level, + ParentID: vendorCategoryID2String(v.ParentID), + } + } + return vendorCats, nil +} + +func vendorCategoryID2String(catID int64) string { + if catID > 0 { + return utils.Int64ToStr(catID) + } + return "" +} diff --git a/business/partner/purchase/weimob/wsc/wsc_test.go b/business/partner/purchase/weimob/wsc/wsc_test.go new file mode 100644 index 000000000..992845fff --- /dev/null +++ b/business/partner/purchase/weimob/wsc/wsc_test.go @@ -0,0 +1,36 @@ +package wsc + +import ( + "testing" + + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/jxutils/tasks" + "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/jx-callback/globals/api" + "git.rosy.net.cn/jx-callback/globals/beegodb" + "github.com/astaxie/beego" +) + +func init() { + //E:/goprojects/src/git.rosy.net.cn/jx-callback/conf/app.conf + ///Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf + beego.InitBeegoBeforeTest("/Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf") + beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test + + globals.Init() + beegodb.Init() + api.Init() + + if err := tasks.RefreshWeimobToken(); err != nil { + globals.SugarLogger.Errorf("RefreshWeimobToken failed with error:%s", err) + return + } +} + +func TestGetVendorCategories(t *testing.T) { + vendorCatList, err := new(PurchaseHandler).GetVendorCategories() + if err != nil { + t.Fatal(err.Error()) + } + globals.SugarLogger.Debug(utils.Format4Output(vendorCatList, false)) +} diff --git a/conf/app.conf b/conf/app.conf index 6c3f65e5d..ec7e012f1 100644 --- a/conf/app.conf +++ b/conf/app.conf @@ -23,6 +23,7 @@ enableStoreWrite = false enableEbaiStoreWrite = false enableElmStoreWrite = true enableMtwmStoreWrite = false +enableWscStoreWrite = false orderUseNewTable = true enablePendingChange = true @@ -101,6 +102,7 @@ dbConnectStr = "root:WebServer@1@tcp(db1.int.jxc4.com:3306)/jxd_dev_0?charset=ut enableStoreWrite = true enableEbaiStoreWrite = true enableMtwmStoreWrite = true +enableWscStoreWrite = true weimobCallbackURL = "http://callback.jxc4.com/weimob" @@ -194,6 +196,7 @@ weixinSecret = "ba32b269a068a5b72486a0beafd171e8" dbConnectStr = "root:WebServer@1@tcp(127.0.0.1:3306)/jxstore_alpha?charset=utf8mb4&loc=Local&parseTime=true" enableStoreWrite = true +enableWscStoreWrite = true [beta] jdToken = "91633f2a-c5f5-4982-a925-a220d19095c3" diff --git a/controllers/init_data.go b/controllers/init_data.go index 20b6f10d9..6db974616 100644 --- a/controllers/init_data.go +++ b/controllers/init_data.go @@ -42,12 +42,13 @@ func (c *InitDataController) InitSkuName() { // @Title 初始化vendor category // @Description 初始化vendor category(当前只有美团外卖的通过这个设置) // @Param token header string true "认证token" +// @Param vendorID formData int true "厂商ID" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /InitVendorCategory [post] func (c *InitDataController) InitVendorCategory() { c.callInitVendorCategory(func(params *tInitdataInitVendorCategoryParams) (retVal interface{}, errCode string, err error) { - retVal, err = initdata.InitVendorCategory(params.Ctx) + retVal, err = initdata.InitVendorCategory(params.Ctx, params.VendorID) return retVal, "", err }) } @@ -87,3 +88,18 @@ func (c *InitDataController) Change2JDSPU4Store() { return retVal, "", err }) } + +// @Title 将SkuName的图片上传到微盟 +// @Description 将SkuName的图片上传到微盟 +// @Param token header string true "认证token" +/// @Param isAsync formData bool false "是否异步操作" +// @Param isContinueWhenError formData bool false "单个同步失败是否继续,缺省false" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /UploadWeimobImg4SkuName [post] +func (c *InitDataController) UploadWeimobImg4SkuName() { + c.callUploadWeimobImg4SkuName(func(params *tInitdataUploadWeimobImg4SkuNameParams) (retVal interface{}, errCode string, err error) { + retVal, err = initdata.UploadWeimobImg4SkuName(params.Ctx, params.IsAsync, params.IsContinueWhenError) + return retVal, "", err + }) +} diff --git a/controllers/weimob_callback.go b/controllers/weimob_callback.go index 0e6d08ae9..ca2dd0896 100644 --- a/controllers/weimob_callback.go +++ b/controllers/weimob_callback.go @@ -2,6 +2,7 @@ package controllers import ( "git.rosy.net.cn/jx-callback/business/jxutils/tasks" + _ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "github.com/astaxie/beego" diff --git a/globals/globals.go b/globals/globals.go index bd9518c7e..9a5fc83d3 100644 --- a/globals/globals.go +++ b/globals/globals.go @@ -28,6 +28,7 @@ var ( EnableEbaiStoreWrite bool EnableElmStoreWrite bool EnableMtwmStoreWrite bool + EnableWscStoreWrite bool EnablePendingChange bool OrderUseNewTable bool @@ -62,6 +63,7 @@ func Init() { EnableEbaiStoreWrite = beego.AppConfig.DefaultBool("enableEbaiStoreWrite", false) EnableElmStoreWrite = beego.AppConfig.DefaultBool("enableElmStoreWrite", false) EnableMtwmStoreWrite = beego.AppConfig.DefaultBool("enableMtwmStoreWrite", false) + EnableWscStoreWrite = beego.AppConfig.DefaultBool("enableWscStoreWrite", false) EnablePendingChange = beego.AppConfig.DefaultBool("enablePendingChange", false) if EnableStore { diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index d8ca6e0a1..cf2b24a6f 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -239,6 +239,14 @@ func init() { MethodParams: param.Make(), Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:InitDataController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:InitDataController"], + beego.ControllerComments{ + Method: "UploadWeimobImg4SkuName", + Router: `/UploadWeimobImg4SkuName`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:MsgController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:MsgController"], beego.ControllerComments{ Method: "GetStoreMessageStatuses",