|
|
|
|
@@ -1,6 +1,7 @@
|
|
|
|
|
package cms
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
@@ -144,6 +145,18 @@ type tGetStoresSkusInfo struct {
|
|
|
|
|
AuditUnitPrice int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type tGetStoresSkusInfoContainCategoryName struct {
|
|
|
|
|
StoreID int `orm:"column(store_id)"`
|
|
|
|
|
StoreName string
|
|
|
|
|
model.SkuName
|
|
|
|
|
PayPercentage int `json:"-"`
|
|
|
|
|
dao.StoreSkuExt
|
|
|
|
|
RealMidUnitPrice int `json:"realMidUnitPrice"` //真实的该商品的全国中位价
|
|
|
|
|
YbSkuName string
|
|
|
|
|
AuditUnitPrice int
|
|
|
|
|
CategoryName string `orm:"column(categoryName)"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type SheetParam struct {
|
|
|
|
|
OutSkuIDCol int
|
|
|
|
|
SkuNameIDCol int
|
|
|
|
|
@@ -2917,6 +2930,224 @@ func GetVendorStoreSkusInfo(ctx *jxcontext.Context, storeID int, vendorIDs, skuI
|
|
|
|
|
return skuVendorMap, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type VendorStoreSkus struct {
|
|
|
|
|
SkuID int `json:"商品ID"` // 两平台共同包含的ID 桥梁
|
|
|
|
|
SkuName string `json:"商品名"`
|
|
|
|
|
Status int `json:"上下架状态"`
|
|
|
|
|
CategoryList []string `json:"商品类别列表"`
|
|
|
|
|
Price int64 `json:"售价"`
|
|
|
|
|
Reason string `json:"原因"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//@creat by 2020-03-09
|
|
|
|
|
//@Description :用于获取第三方平台一个门店下所有的商品数据
|
|
|
|
|
func GetVendorStoreSkusToStruct(ctx *jxcontext.Context, storeID, vendorID int) (err error) {
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
db = dao.GetDB()
|
|
|
|
|
vendorStoreSkus []*VendorStoreSkus
|
|
|
|
|
excelTitle = []string{
|
|
|
|
|
"商品ID",
|
|
|
|
|
"商品名",
|
|
|
|
|
"上下架状态",
|
|
|
|
|
"商品类别列表",
|
|
|
|
|
"售价",
|
|
|
|
|
"原因",
|
|
|
|
|
}
|
|
|
|
|
sheetList []*excel.Obj2ExcelSheetConfig
|
|
|
|
|
downloadURL, fileName string
|
|
|
|
|
)
|
|
|
|
|
storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID, "")
|
|
|
|
|
if err != nil || storeDetail == nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if partner.IsMultiStore(vendorID) {
|
|
|
|
|
// handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
|
|
|
|
|
// skuBareInfoList, _ := handler.GetStoreSkusBareInfo(ctx, storeDetail.VendorOrgCode, nil, storeID, storeDetail.VendorStoreID, nil)
|
|
|
|
|
return fmt.Errorf("暂不支持京东!")
|
|
|
|
|
} else {
|
|
|
|
|
handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
|
|
|
|
|
// 使用处理器获取后台所有的商品 存入一个Slice中
|
|
|
|
|
skuList, _ := handler.GetStoreSkusFullInfo(ctx, nil, storeID, storeDetail.VendorStoreID, nil)
|
|
|
|
|
// 设置一个默认原因
|
|
|
|
|
var defaultReason = "不存在该商品待同步"
|
|
|
|
|
for _, sku := range skuList {
|
|
|
|
|
skus := &VendorStoreSkus{
|
|
|
|
|
SkuID: sku.NameID,
|
|
|
|
|
SkuName: sku.Name,
|
|
|
|
|
Status: sku.Status,
|
|
|
|
|
CategoryList: sku.VendorCatIDList,
|
|
|
|
|
Price: sku.SkuList[0].VendorPrice,
|
|
|
|
|
Reason: defaultReason,
|
|
|
|
|
}
|
|
|
|
|
vendorStoreSkus = append(vendorStoreSkus, skus)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tmpList, err := GetLocalStoreSkusByStoreID(storeID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
globals.SugarLogger.Debug(err)
|
|
|
|
|
} else {
|
|
|
|
|
globals.SugarLogger.Debug(len(tmpList))
|
|
|
|
|
if len(tmpList) == 0 { //数据库中无匹配项 直接将第三方数据进行导出
|
|
|
|
|
goto creatExec
|
|
|
|
|
} else { //进行比较
|
|
|
|
|
if result := ComPareLocalWithVendors(tmpList, vendorStoreSkus); result != nil {
|
|
|
|
|
// 将返回的切片进行覆盖
|
|
|
|
|
vendorStoreSkus = result
|
|
|
|
|
goto creatExec
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
creatExec:
|
|
|
|
|
excelConf := &excel.Obj2ExcelSheetConfig{
|
|
|
|
|
Title: "sheet1",
|
|
|
|
|
Data: vendorStoreSkus,
|
|
|
|
|
CaptionList: excelTitle,
|
|
|
|
|
}
|
|
|
|
|
sheetList = append(sheetList, excelConf)
|
|
|
|
|
if excelConf != nil {
|
|
|
|
|
downloadURL, fileName, err = jxutils.UploadExeclAndPushMsg(sheetList, "比较差异")
|
|
|
|
|
} else {
|
|
|
|
|
baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess is nil!")
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName, err)
|
|
|
|
|
} else {
|
|
|
|
|
noticeMsg := fmt.Sprintf("[详情点我]%s/billshow/?normal=true&path=%s \n", globals.BackstageHost, downloadURL)
|
|
|
|
|
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, ctx.GetUserID(), "异步任务完成", noticeMsg)
|
|
|
|
|
baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess downloadURL: [%v]", downloadURL)
|
|
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 通过门店ID 查询数据库对应门店商品管理按SKU查询门店下的所有商品
|
|
|
|
|
func GetLocalStoreSkusByStoreID(storeID int) (tmp []*tGetStoresSkusInfoContainCategoryName, err error) {
|
|
|
|
|
sql := `
|
|
|
|
|
SELECT SQL_CALC_FOUND_ROWS
|
|
|
|
|
t3.id store_id, t3.name store_name, t3.pay_percentage,
|
|
|
|
|
t1.*,
|
|
|
|
|
t2.name_id, t2.id sku_id, t2.spec_quality sku_spec_quality, t2.spec_unit sku_spec_unit, t2.weight, t2m.vendor_thing_id sku_jd_id,
|
|
|
|
|
t2.comment, t2.category_id sku_category_id, t2.status sku_status, t2.eclp_id,
|
|
|
|
|
t4.created_at bind_created_at, t4.updated_at bind_updated_at, t4.last_operator bind_last_operator, t4.deleted_at bind_deleted_at,
|
|
|
|
|
t4.sub_store_id, t4.price bind_price, IF(t4.unit_price IS NOT NULL, t4.unit_price, t1.price) unit_price, t4.status store_sku_status, t4.auto_sale_at,
|
|
|
|
|
t4.ebai_id, t4.mtwm_id, t4.yb_id, CONCAT(smm.yb_store_prefix,t1.yb_name_suffix) yb_sku_name, t4.jds_id, t4.jds_ware_id,
|
|
|
|
|
t4.jd_sync_status, t4.ebai_sync_status, t4.mtwm_sync_status, t4.yb_sync_status, t4.jds_sync_status,
|
|
|
|
|
t4.jd_price, t4.ebai_price, t4.mtwm_price, t4.jx_price, t4.yb_price, t4.jds_price,
|
|
|
|
|
t4.jd_lock_time, t4.ebai_lock_time, t4.mtwm_lock_time, t4.jx_lock_time, t4.yb_lock_time, t4.jds_lock_time,
|
|
|
|
|
t4.status_sale_begin, t4.status_sale_end, t4.stock, t4.mt_ladder_box_price,
|
|
|
|
|
t6.mid_unit_price real_mid_unit_price,
|
|
|
|
|
t7.unit_price audit_unit_price,
|
|
|
|
|
t8.name categoryName
|
|
|
|
|
FROM sku_name t1
|
|
|
|
|
JOIN sku t2 FORCE INDEX(PRIMARY) ON t1.id = t2.name_id AND t2.deleted_at = '1970-01-01 00:00:00 +0800'
|
|
|
|
|
JOIN store t3 ON t3.deleted_at = '1970-01-01 00:00:00 +0800'
|
|
|
|
|
LEFT JOIN store_map sm ON sm.store_id = t3.id AND sm.vendor_id = 0 AND sm.deleted_at = '1970-01-01 00:00:00 +0800'
|
|
|
|
|
LEFT JOIN store_map smm ON smm.store_id = t3.id AND smm.deleted_at = '1970-01-01 00:00:00 +0800' AND smm.vendor_id = 4
|
|
|
|
|
LEFT JOIN thing_map t2m ON t2m.thing_type = 3 AND t2m.thing_id = t2.id AND t2m.vendor_id = sm.vendor_id AND t2m.vendor_org_code = sm.vendor_org_code AND t2m.deleted_at = '1970-01-01 00:00:00 +0800'
|
|
|
|
|
|
|
|
|
|
JOIN store_sku_bind t4 ON t4.store_id = t3.id AND t4.sku_id = t2.id AND t4.deleted_at = '1970-01-01 00:00:00 +0800'
|
|
|
|
|
LEFT JOIN sku_name_place_bind t5 ON t1.id = t5.name_id AND t3.city_code = t5.place_code
|
|
|
|
|
LEFT JOIN price_refer_snapshot t6 ON t6.city_code = 0 AND t6.sku_id = t2.id AND t6.snapshot_at = '2099-03-08 00:00:00 +0800'
|
|
|
|
|
LEFT JOIN store_sku_audit t7 ON t7.store_id = t3.id AND t7.name_id = t1.id AND t7.status = 0 AND t7.deleted_at = '1970-01-01 00:00:00 +0800'
|
|
|
|
|
LEFT JOIN sku_category t8 ON t1.category_id= t8.id
|
|
|
|
|
WHERE t1.deleted_at = '1970-01-01 00:00:00 +0800' AND (t1.is_global = 1 OR t5.id IS NOT NULL OR 1 = 1)
|
|
|
|
|
AND ((t2.status = 1 AND t1.status = 1) OR t4.status = 1) AND t3.id IN (?) AND IF(INSTR(t3.name,'饿鲜达') > 0, t2.exd_sku_id <> '', t2.exd_sku_id = '') AND t4.status >= 0 AND t4.status <= 1 AND t4.unit_price <= 99900 AND t4.unit_price >= 0
|
|
|
|
|
ORDER BY t3.id, t2.name_id, t2.id`
|
|
|
|
|
var tmpList []*tGetStoresSkusInfoContainCategoryName
|
|
|
|
|
txDB, _ := dao.Begin(dao.GetDB())
|
|
|
|
|
if err = dao.GetRowsTx(txDB, &tmpList, sql, storeID); err != nil {
|
|
|
|
|
dao.Rollback(dao.GetDB(), txDB)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return tmpList, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 比较本地和第三方平台的差异 返回一个Excel 可接收实体
|
|
|
|
|
func ComPareLocalWithVendors(localSku []*tGetStoresSkusInfoContainCategoryName, vendorSkus []*VendorStoreSkus) (result []*VendorStoreSkus) {
|
|
|
|
|
// 进行取参比较
|
|
|
|
|
var localStoreSkus []*VendorStoreSkus
|
|
|
|
|
var updateStoreSkus []*VendorStoreSkus
|
|
|
|
|
var defaultReason = "平台不存在该商品待同步"
|
|
|
|
|
for _, sku := range localSku {
|
|
|
|
|
skus := &VendorStoreSkus{
|
|
|
|
|
SkuID: sku.StoreSkuExt.SkuID,
|
|
|
|
|
SkuName: sku.SkuName.Name,
|
|
|
|
|
Status: sku.Status,
|
|
|
|
|
CategoryList: jxStatusTransForm(sku.CategoryName), //此处需要使用函数进行转换 进行查询根据类别ID去sku_category查询返回一个子类别放入List中
|
|
|
|
|
Price: vendorPriceTransForm(&sku.StoreSkuExt, 1), //此处需要使用函数转换传入一个VendorID进行比较根据ID的不同返回对应不同的字段
|
|
|
|
|
Reason: defaultReason,
|
|
|
|
|
}
|
|
|
|
|
localStoreSkus = append(localStoreSkus, skus)
|
|
|
|
|
}
|
|
|
|
|
globals.SugarLogger.Debug(localStoreSkus, vendorSkus)
|
|
|
|
|
// 由于go语言中无法子定义struct比较规则 因此需要把数据提取出来进行处理
|
|
|
|
|
// 进行比较处理 对两个slice 进行遍历 放到map中 以 skuID slice的形式进行存储 如果不存在则直接进行put操作 如果存在则进行比较类别,价格,以及上下架状态
|
|
|
|
|
compareMap := make(map[int]*VendorStoreSkus)
|
|
|
|
|
for _, local := range localStoreSkus {
|
|
|
|
|
compareMap[local.SkuID] = local
|
|
|
|
|
}
|
|
|
|
|
for _, vendorSku := range vendorSkus {
|
|
|
|
|
if value, ok := compareMap[vendorSku.SkuID]; ok { //进行逻辑处理
|
|
|
|
|
// 进行比较 如果同时满足价格状态以及末级类别 则进行remove操作 否则什么也不做
|
|
|
|
|
if value.Price == vendorSku.Price && value.Status == vendorSku.Status && value.CategoryList[0] == vendorSku.CategoryList[len(vendorSku.CategoryList)-1] {
|
|
|
|
|
delete(compareMap, vendorSku.SkuID)
|
|
|
|
|
} else { //对原因进行赋值并展示出来
|
|
|
|
|
//需要考虑是否存在多种情况并存的情况可以更直观的看出差异所在
|
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
|
var count = 1
|
|
|
|
|
if value.Price != vendorSku.Price {
|
|
|
|
|
buffer.WriteString(strconv.Itoa(count))
|
|
|
|
|
buffer.WriteString(".")
|
|
|
|
|
buffer.WriteString("价格不同步,平台价格:" + strconv.FormatInt(vendorSku.Price, 10))
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
if value.Status != vendorSku.Status {
|
|
|
|
|
buffer.WriteString(strconv.Itoa(count))
|
|
|
|
|
buffer.WriteString(".")
|
|
|
|
|
buffer.WriteString("商品上下架状态不一致")
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
if value.CategoryList[0] != vendorSku.CategoryList[len(vendorSku.CategoryList)-1] {
|
|
|
|
|
buffer.WriteString(strconv.Itoa(count))
|
|
|
|
|
buffer.WriteString(".")
|
|
|
|
|
buffer.WriteString("类别不一致:平台类别为" + vendorSku.CategoryList[len(vendorSku.CategoryList)-1])
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
value.Reason = buffer.String()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, v := range compareMap {
|
|
|
|
|
updateStoreSkus = append(updateStoreSkus, v)
|
|
|
|
|
}
|
|
|
|
|
globals.SugarLogger.Debug(updateStoreSkus)
|
|
|
|
|
return updateStoreSkus
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func jxStatusTransForm(categoryName string) []string {
|
|
|
|
|
var result []string
|
|
|
|
|
result = append(result, categoryName)
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据不同平台判断返回不同的价格类型
|
|
|
|
|
func vendorPriceTransForm(storeSkuExt *dao.StoreSkuExt, vendorID int) int64 {
|
|
|
|
|
switch vendorID {
|
|
|
|
|
case 1:
|
|
|
|
|
return int64(storeSkuExt.MtwmPrice)
|
|
|
|
|
case 0:
|
|
|
|
|
return int64(storeSkuExt.JdPrice)
|
|
|
|
|
case 3:
|
|
|
|
|
return int64(storeSkuExt.EbaiPrice)
|
|
|
|
|
case 4:
|
|
|
|
|
return int64(storeSkuExt.YbPrice)
|
|
|
|
|
case 5:
|
|
|
|
|
return int64(storeSkuExt.JdsPrice)
|
|
|
|
|
default:
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
func SyncJdStoreProducts(ctx *jxcontext.Context, storeIDs, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
|
|
|
|
db := dao.GetDB()
|
|
|
|
|
isManageIt := len(storeIDs) != 1 || len(skuIDs) == 0 || len(skuIDs) > 8
|
|
|
|
|
|