Files
jx-callback/business/enterprise/vendor_sku_compare.go
邹宗楠 4be0560888 1
2025-03-21 13:46:45 +08:00

483 lines
18 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 enterprise
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
tao "git.rosy.net.cn/baseapi/platformapi/tao_vegetable"
domain585 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability585/domain"
request585 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability585/request"
product_listV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/request"
product_listV2_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/response"
sku_syncStock_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/sku_syncStock/request"
"git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"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/apimanager"
beego "github.com/astaxie/beego/server/web"
"strings"
)
// 该函数主要用于对比京西平台商品和各个平台门店商品的差异
// 对比上下架状态以及商品价格差异,相同的不做修改,不同的以京西系统商品为主
func CompareJxVendorSku(jxStoreId int, vendorIds []int) (string, error) {
var (
db = dao.GetDB()
errListToStr = new(strings.Builder)
)
skuList, err := dao.GetStoresSkusInfo(db, []int{jxStoreId}, nil)
if err != nil {
return "", err
}
// 门店商品列表平
skuMap := make(map[string]*model.StoreSkuBind, 0)
skuIdList := make([]string, 0, len(skuList))
for _, v := range skuList {
localSkuId := utils.Int2Str(v.SkuID)
skuMap[localSkuId] = v
skuIdList = append(skuIdList, localSkuId)
}
// 有效的三方平台
storeMap, err := dao.GetStoresMapList(db, vendorIds, []int{jxStoreId}, []int{model.StoreStatusOpened, model.StoreStatusClosed, model.StoreStatusHaveRest}, model.StoreStatusDisabled, 1, "", "", "")
if err != nil {
return "", err
}
for _, sm := range storeMap {
switch sm.VendorID {
case model.VendorIDJD:
if errs := JdSyncSkuPriceAndStatus(db, sm, skuMap); err != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("京东同步商品异常信息: %v", errs)
}
continue
case model.VendorIDMTWM:
if errs := MtWmSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("美团同步商品异常信息: %v", errs)
}
continue
case model.VendorIDEBAI:
if errs := EBaiSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("饿百同步商品异常信息: %v", errs)
}
continue
case model.VendorIDDD:
if errs := TiktokSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("抖音同步商品异常信息: %v", errs)
}
continue
case model.VendorIDTaoVegetable:
if errs := TaoSyncSkuPriceAndStatus(db, sm, skuMap, skuIdList); errs != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("淘宝同步商品异常信息: %v", errs)
}
continue
default:
return errListToStr.String(), fmt.Errorf("无法识别的平台id")
}
}
return "", err
}
// MtWmSyncSkuPriceAndStatus 校验美团平台和京西系统商品差异
func MtWmSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
var (
mtApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*mtwmapi.API)
i = model.NO
foodListData = make([]*mtwmapi.AppFood, 0, 0)
errs = make([]string, 0, 0)
vendorStatus = 0
)
if len(skuMap) == 0 || sm.IsSync != model.YES {
return fmt.Errorf("门店未打开同步或者未关注商品")
}
if sm.VendorOrgCode == globals.Mtwm2Code {
mtApi = mtwmapi.New(beego.AppConfig.DefaultString("mtwmAppID2", ""), beego.AppConfig.DefaultString("mtwmSecret2", ""), beego.AppConfig.DefaultString("mtwmCallbackURL2", ""), "")
mtApi.SetToken(sm.MtwmToken)
} else {
mtApi = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, sm.VendorOrgCode).(*mtwmapi.API)
}
for {
foodList, err := mtApi.RetailListAll(sm.VendorStoreID, i)
if err != nil {
globals.SugarLogger.Debugf("美团商品价格和上下架状态获取平台商品异常 :%v", err)
break
}
foodListData = append(foodListData, foodList...)
if len(foodList) < 100 {
break
}
i++
}
for _, vsl := range foodListData {
if sku, ok := skuMap[vsl.AppFoodCode]; ok {
// 同步商品价格
if utils.Float64TwoInt(vsl.Price*float64(100)) != sku.MtwmPrice {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团价格错误:%v", sku.SkuID, err))
}
}
// 同步商品上下架状态
// SPU可能包含多个SKU上下架状态字段取值范围0-全部sku上架1-全部sku下架。以下功能灰度中若同时传递sku_is_sold_out则优先根据sku_is_sold_out传参判断单个sku的上下架状态。
// 本地sku.Status 0-不可售, 1-可售
if vsl.IsSoldOut == sku.Status {
if sku.Status == model.SkuStatusNormal {
vendorStatus = mtwmapi.SellStatusOnline
} else {
vendorStatus = mtwmapi.SellStatusOffline
}
param := []*mtwmapi.BareStoreFoodInfo{
&mtwmapi.BareStoreFoodInfo{
AppFoodCode: utils.Int64ToStr(sku.MtwmID),
Skus: nil,
},
}
foodErrList, err := mtApi.RetailSellStatus(jxcontext.AdminCtx.GetTrackInfo(), sm.VendorStoreID, param, vendorStatus)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团可售状态错误%v", sku.SkuID, err))
}
for _, fel := range foodErrList {
errs = append(errs, fmt.Sprintf("skuCode:%s,修改美团可售状态错误:%s", fel.AppFoodCode, fel.ErrorMsg))
}
}
} else {
param := []*mtwmapi.BareStoreFoodInfo{
&mtwmapi.BareStoreFoodInfo{
AppFoodCode: vsl.AppFoodCode,
Skus: nil,
},
}
foodErrList, err := mtApi.RetailSellStatus(jxcontext.AdminCtx.GetTrackInfo(), sm.VendorStoreID, param, mtwmapi.SellStatusOffline)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团可售状态错误%v", vsl.AppFoodCode, err))
}
for _, fel := range foodErrList {
errs = append(errs, fmt.Sprintf("skuCode:%s,修改美团可售状态错误:%s", fel.AppFoodCode, fel.ErrorMsg))
}
}
}
if len(errs) == model.NO {
return nil
}
return fmt.Errorf("%s", strings.Join(errs, ","))
}
// EBaiSyncSkuPriceAndStatus 校验饿了么平台和京西系统商品差异
func EBaiSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
var (
ebaiApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*ebaiapi.API)
//skuIdOffset = 0
foodListData = make([]*ebaiapi.SkuInfo, 0, 0)
errs = make([]string, 0, 0)
)
if len(skuMap) == 0 || sm.IsSync != model.YES {
return fmt.Errorf("门店未打开同步或者未关注商品")
}
for {
page := 1
param := &ebaiapi.SkuListParams{
Page: page,
PageSize: 100,
//SkuIdOffset: skuIdOffset,
}
foodList, err := ebaiApi.SkuList(utils.Int2Str(sm.StoreID), param)
if err != nil {
globals.SugarLogger.Debugf("饿了么商品价格和上下架状态获取平台商品异常 :%v", err)
break
}
foodListData = append(foodListData, foodList.List...)
if len(foodList.List) < 100 {
break
}
//skuIdOffset = foodList.SkuIdOffset
page += 1
}
globals.SugarLogger.Debugf("======len foodListData:= %d", len(foodListData))
globals.SugarLogger.Debugf("======len skuMap:= %d", len(skuMap))
for _, vsl := range foodListData {
if sku, ok := skuMap[vsl.CustomSkuId]; ok {
// 同步商品价格
if vsl.SalePrice != sku.EbaiPrice {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
}
// 同步商品上下架状态
// 1为上架0为下架
// 本地sku.Status 0-不可售, 1-可售
if vsl.Status != utils.Int2Str(sku.Status) {
// 平台上架本地下架,将平台商品下架
if sku.Status == model.StoreSkuBindStatusNormal {
ebailResult, err := ebaiApi.SkuOnline(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), []int64{sku.EbaiID}, nil, nil)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
}
for _, fel := range ebailResult.FailedList {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrorMsg))
}
} else {
err = ebaiApi.SkuOfflineOne(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), sku.EbaiID, "", "")
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百不可售状态错误%v", sku.SkuID, err))
}
}
}
} else {
_, err = ebaiApi.SkuDelete(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), nil, []string{vsl.CustomSkuId})
//err = ebaiApi.SkuOfflineOne(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), utils.Str2Int64(vsl.CustomSkuId), "", "")
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百不可售状态错误%v", sku.SkuID, err))
}
}
}
if len(errs) == model.NO {
return nil
}
return fmt.Errorf("%s", strings.Join(errs, ","))
}
// TaoSyncSkuPriceAndStatus 校验淘宝平台和京西系统商品差异
func TaoSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind, skuIdList []string) (err error) {
var (
taoApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*tao.API)
length = len(skuIdList) / 100
foodListData = make([]domain585.AlibabaWdkSkuQuerySkuDo, 0, 0)
onlineStatus int64 = 0
)
if len(skuMap) == 0 || sm.IsSync != model.YES {
return fmt.Errorf("门店未打开同步或者未关注商品")
}
if len(skuIdList)%100 != 0 {
length += 1
}
// 获取平台商品列表
for i := 0; i < length; i++ {
skuCods := skuIdList[i*100 : (i+1)*100]
foodList, _ := taoApi.QueryStoreSKu(&request585.AlibabaWdkSkuQueryRequest{Param: &domain585.AlibabaWdkSkuQuerySkuQueryDo{
OuCode: utils.String2Pointer(sm.VendorStoreID),
SkuCodes: &skuCods,
}})
for _, fl := range *foodList {
if *fl.Success {
foodListData = append(foodListData, *fl.Model)
}
}
}
// 比较商品差异
errs := make([]string, 0, 0)
for _, vsl := range foodListData {
if sku, ok := skuMap[*vsl.SkuCode]; ok {
// 同步商品价格
if utils.Float64TwoInt(utils.Str2Float64(*vsl.SalePrice)*float64(100)) != sku.TaoPrice {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
if err != nil {
errs = append(errs, fmt.Sprintf("淘宝对比商品价格异常skuid:%d,错误%v", sku.SkuID, err))
}
}
// 同步商品上下架状态
// 是否线上可售 是 0否 1是。
// 本地sku.Status 0-不可售, 1-可售
if int(*vsl.OnlineSaleFlag) != sku.Status {
// 平台上架本地下架,将平台商品下架
param := &request585.AlibabaWdkSkuUpdateRequest{}
updateSkuList := make([]domain585.AlibabaWdkSkuUpdateSkuDo, 0, 0)
if sku.Status == model.SkuStatusNormal {
onlineStatus = tao.CreateOnlineSaleFlag
} else {
onlineStatus = tao.CreateOfflineSaleFlag
}
updateSkuList = append(updateSkuList, domain585.AlibabaWdkSkuUpdateSkuDo{
OuCode: utils.String2Pointer(utils.Int64ToStr(sku.TaoID)),
SkuCode: utils.String2Pointer(utils.Int2Str(sku.SkuID)),
OnlineSaleFlag: utils.Int64ToPointer(onlineStatus),
SubTitle: utils.String2Pointer("小时达"),
AllowAppSale: utils.Int64ToPointer(onlineStatus),
//CleanSkuMemberPrice: utils.Int64ToPointer(model.YES),
})
param.ParamList = &updateSkuList
result, err := taoApi.UpdateStoreSku(param)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
}
for _, fel := range *result {
if fel.ErrMsg != "" {
errs = append(errs, fmt.Sprintf("skuCode:%s,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrMsg))
}
}
//_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, 56, true, true)
//if err != nil {
// errs = append(errs, fmt.Sprintf("%v", err))
//}
}
} else {
// 平台上架本地下架,将平台商品下架
param := &request585.AlibabaWdkSkuUpdateRequest{}
updateSkuList := make([]domain585.AlibabaWdkSkuUpdateSkuDo, 0, 0)
onlineStatus = tao.CreateOfflineSaleFlag
updateSkuList = append(updateSkuList, domain585.AlibabaWdkSkuUpdateSkuDo{
OuCode: vsl.OuCode,
SkuCode: vsl.SkuCode,
OnlineSaleFlag: utils.Int64ToPointer(onlineStatus),
SubTitle: utils.String2Pointer("小时达"),
AllowAppSale: utils.Int64ToPointer(onlineStatus),
//CleanSkuMemberPrice: utils.Int64ToPointer(model.YES),
})
param.ParamList = &updateSkuList
result, err := taoApi.UpdateStoreSku(param)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
}
for _, fel := range *result {
if fel.ErrMsg != "" {
errs = append(errs, fmt.Sprintf("skuCode:%s,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrMsg))
}
}
}
}
if len(errs) == model.NO {
return nil
}
return fmt.Errorf("%s", strings.Join(errs, ","))
}
// TiktokSyncSkuPriceAndStatus 校验抖音平台和京西系统商品差异
func TiktokSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
var (
tiktokApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*tiktok_api.API)
page = 0
foodListData = make([]product_listV2_response.DataItem, 0, 0)
errs = make([]string, 0, 0)
)
if len(skuMap) == 0 || sm.IsSync != model.YES {
return fmt.Errorf("门店未打开同步或者未关注商品")
}
for {
param := &product_listV2_request.ProductListV2Param{
Page: int64(page),
Size: 100,
StoreId: utils.Str2Int64(sm.VendorStoreID),
}
foodList, err := tiktokApi.GetSkuDetailList(param)
if err != nil {
globals.SugarLogger.Debugf("抖音商品价格和上下架状态获取平台商品异常 :%v", err)
break
}
foodListData = append(foodListData, foodList.Data...)
if len(foodList.Data) < 100 {
break
}
page += 1
}
for _, vsl := range foodListData {
if sku, ok := skuMap[vsl.OuterProductId]; ok {
// 同步商品价格
if vsl.DiscountPrice != int64(sku.DdPrice) {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
if err != nil {
errs = append(errs, fmt.Sprintf("抖音对比商品价格异常skuid:%d,错误%v", sku.SkuID, err))
}
}
// 同步商品上下架状态
// 0-在线 1-下线
// 本地sku.Status 0-不可售,1-可售
if vsl.Status == int64(sku.Status) {
if sku.Status == model.SkuStatusNormal {
param := &sku_syncStock_request.SkuSyncStockParam{
ProductId: sku.DdID,
Incremental: false,
StockNum: 99999,
OutSkuId: int64(sku.SkuID),
}
if err = tiktokApi.UpdateSkuStock(param); err != nil {
errs = append(errs, fmt.Sprintf("抖音对比商品上架异常skuid:%d,错误%v", sku.SkuID, err))
}
} else {
param := &sku_syncStock_request.SkuSyncStockParam{
ProductId: sku.DdID,
Incremental: false,
StockNum: 0,
OutSkuId: int64(sku.SkuID),
}
if err = tiktokApi.UpdateSkuStock(param); err != nil {
errs = append(errs, fmt.Sprintf("抖音对比商品下架异常skuid:%d,错误%v", sku.SkuID, err))
}
}
}
} else {
param := &sku_syncStock_request.SkuSyncStockParam{
ProductId: sku.DdID,
Incremental: false,
StockNum: 0,
OutSkuId: int64(sku.SkuID),
}
if err = tiktokApi.UpdateSkuStock(param); err != nil {
errs = append(errs, fmt.Sprintf("抖音对比商品下架异常skuid:%d,错误%v", sku.SkuID, err))
}
}
}
if len(errs) == model.NO {
return nil
}
return fmt.Errorf("%s", strings.Join(errs, ","))
}
// JdSyncSkuPriceAndStatus 校验京东平台和京西系统商品差异
func JdSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
var (
jdsApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*jdapi.API)
)
skuVendibilityList := make([]*jdapi.StockVendibility, 0, 0)
for _, v := range skuMap {
skuVendibilityList = append(skuVendibilityList, &jdapi.StockVendibility{
OutSkuId: utils.Int2Str(v.SkuID),
DoSale: v.Status == model.SkuStatusNormal,
})
}
count := len(skuVendibilityList) / 50
if len(skuVendibilityList)%50 != 0 {
count += 1
}
for i := 1; i <= count; i++ {
if i == count {
jdsApi.BatchUpdateVendibility(jxcontext.AdminCtx.GetTrackInfo(), "", sm.VendorStoreID, skuVendibilityList[(i-1)*50:], jxcontext.AdminCtx.GetUserName())
} else {
jdsApi.BatchUpdateVendibility(jxcontext.AdminCtx.GetTrackInfo(), "", sm.VendorStoreID, skuVendibilityList[(i-1)*50:i*50], jxcontext.AdminCtx.GetUserName())
}
}
return fmt.Errorf("京东运行结束")
}