Files
jx-callback/business/jxstore/cms/sku.go
2020-04-27 14:08:27 +08:00

2436 lines
78 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 cms
import (
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"regexp"
"strconv"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/aliupcapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"github.com/360EntSecGroup-Skylar/excelize"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/globals/refutil"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/datares"
"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"
)
type SkuNamesInfo struct {
TotalCount int `json:"totalCount"`
SkuNames []*model.SkuNameExt `json:"skuNames"`
}
type CreateUpcSkuByExcelErr struct {
Upc string `json:"商品条码"`
Name string `json:"商品名称"`
Unit string `json:"单位"`
SpecQuality string `json:"重量(g)"`
Price int `json:"售价"`
Err string `json:"错误原因"`
}
var (
ErrInputCatsDoesntMatch = errors.New("输入的类别列表不合法需要输入一个父ID下的所有子类别")
)
var (
ebaiUploadRTFShopID string // 饿百找一个店用于调用SkuUploadRTF
)
var (
sendNoCatSkusMobile = []string{
"18048531223",
"18982250714",
}
)
// func getAndSetEbaiUploadRTFShopID() (shopID string) {
// if ebaiUploadRTFShopID == "" {
// if storeDetail, err := dao.GetStoreDetail(dao.GetDB(), 0, model.VendorIDEBAI); err == nil {
// ebaiUploadRTFShopID = utils.Int2Str(storeDetail.Store.ID)
// }
// }
// return ebaiUploadRTFShopID
// }
// parentID 为-1表示所有
func GetVendorCategories(ctx *jxcontext.Context, vendorID int, parentID string) (vendorCats []*model.SkuVendorCategory, err error) {
cond := map[string]interface{}{
model.FieldVendorID: vendorID,
}
if parentID != "-1" {
cond[model.FieldParentID] = parentID
}
return vendorCats, dao.GetEntitiesByKV(nil, &vendorCats, cond, false)
}
// parentID 为-1表示所有
func GetCategories(ctx *jxcontext.Context, parentID int, isExd bool) (catList []*dao.SkuCategoryWithVendor, err error) {
db := dao.GetDB()
cats, err := dao.GetCategories(db, parentID, 0, nil, isExd)
if err == nil {
var ids []int
for _, v := range cats {
ids = append(ids, v.ID)
}
thingMapMap, err2 := dao.GetThingMapMap(db, model.ThingTypeCategory, nil, ids)
// globals.SugarLogger.Debug(utils.Format4Output(thingMapMap, false))
if err = err2; err == nil {
for _, v := range cats {
catList = append(catList, &dao.SkuCategoryWithVendor{
SkuCategory: v,
MapList: thingMapMap[int64(v.ID)],
})
}
}
}
return catList, err
}
func AddCategory(ctx *jxcontext.Context, cat *model.SkuCategory, userName string) (outCat *model.SkuCategory, err error) {
db := dao.GetDB()
if cat.Level < 0 || cat.Level > 2 {
return nil, errors.New("Level必须为1或2")
} else if cat.Level == 1 && cat.ParentID != 0 {
return nil, errors.New("Level1的分类其父分类必须为0")
} else if cat.Level == 2 {
if cat.ParentID == 0 {
return nil, errors.New("Level2的分类其父分类必须不为0")
}
parentCat := &model.SkuCategory{}
parentCat.ID = cat.ParentID
if err = dao.GetEntity(db, parentCat); err != nil {
return nil, err
}
if parentCat.Level != 1 {
return nil, errors.New("Level2的分类其父分类必须为Level1分类")
}
}
dao.WrapAddIDCULDEntity(cat, userName)
// cat.JdSyncStatus = model.SyncFlagNewMask
// cat.JdID = 0
cat.Status = model.CategoryStatusEnable
cat.Name = strings.Trim(cat.Name, " ")
if cat.Img != "" {
_, err2 := datares.TryRegisterDataResource(ctx, cat.Name, cat.Img, model.ImgTypeLocal, false)
if err = err2; err != nil {
return nil, err
}
}
if cat.Seq <= 0 {
var maxSeq struct {
MaxSeq int
}
if err = dao.GetRow(db, &maxSeq, "SELECT MAX(seq) max_seq FROM sku_category t1 WHERE level = ?", cat.Level); err != nil {
return nil, err
}
cat.Seq = maxSeq.MaxSeq + 1
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if err = dao.CreateEntity(db, cat); err != nil {
dao.Rollback(db)
return nil, err
}
if cat.IsExdSpec == model.NO {
if err = OnCreateThing(ctx, db, nil, int64(cat.ID), model.ThingTypeCategory); err != nil {
dao.Rollback(db)
return nil, err
}
}
dao.Commit(db)
outCat = cat
_, err = CurVendorSync.SyncCategory(ctx, nil, cat.ID, false, userName)
return outCat, err
}
func UpdateCategory(ctx *jxcontext.Context, categoryID int, payload map[string]interface{}, userName string) (num int64, err error) {
cat := &model.SkuCategory{}
cat.ID = categoryID
db := dao.GetDB()
if err = dao.GetEntity(db, cat); err != nil {
return 0, err
}
for k, v := range payload {
if v == nil {
delete(payload, k)
}
}
valid := dao.StrictMakeMapByStructObject(payload, cat, userName)
if len(valid) > 0 {
// syncStatus := 0
// if valid["name"] != nil {
// valid["name"] = strings.Trim(valid["name"].(string), " ")
// syncStatus = model.SyncFlagModifiedMask
// valid[model.FieldJdSyncStatus] = int8(syncStatus) | cat.JdSyncStatus
// }
if valid["status"] != nil {
if utils.Interface2Int64WithDefault(valid["status"], -1) == model.CategoryStatusDisabled {
if skuList, err2 := dao.GetSkuByCats(db, []int{categoryID}); err2 == nil && len(skuList) > 0 {
return 0, fmt.Errorf("暂不允许禁用分类下有商品的分类!")
}
}
}
if valid["img"] != nil {
if imgStr := utils.Interface2String(valid["img"]); imgStr != "" {
_, err2 := datares.TryRegisterDataResource(ctx, cat.Name, utils.Interface2String(valid["img"]), model.ImgTypeLocal, false)
if err = err2; err != nil {
return 0, err
}
}
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if num, err = dao.UpdateEntityLogically(db, cat, valid, userName, nil); err != nil {
dao.Rollback(db)
return 0, err
}
if cat.IsExdSpec == model.NO {
if err = OnUpdateThing(ctx, db, nil, int64(categoryID), model.ThingTypeCategory); err != nil {
dao.Rollback(db)
return 0, err
}
}
dao.Commit(db)
SetStoreCategorySyncStatus2(db, nil, []int{categoryID}, model.SyncFlagModifiedMask)
var skuIDs []int
if valid["jdCategoryID"] != nil || valid["ebaiCategoryID"] != nil || valid["mtwmCategoryID"] != nil ||
valid["jdPricePercentage"] != nil || valid["ebaiPricePercentage"] != nil || valid["mtwmPricePercentage"] != nil {
if skuList, err2 := dao.GetSkuByCats(db, []int{categoryID}); err2 == nil && len(skuList) > 0 {
for _, sku := range skuList {
skuIDs = append(skuIDs, sku.ID)
}
if valid["jdCategoryID"] != nil {
dao.SetSkuSyncStatus(db, model.VendorIDJD, skuIDs, model.SyncFlagModifiedMask)
}
// todo 如下逻辑在不同平台同时改pricePercentage与平台分类映射时会不必要的打上多余的标记
var vendorIDs []int
syncStatus := model.SyncFlagModifiedMask
if valid["jdPricePercentage"] != nil {
vendorIDs = append(vendorIDs, model.VendorIDJD)
syncStatus |= model.SyncFlagPriceMask
}
if valid["ebaiPricePercentage"] != nil {
vendorIDs = append(vendorIDs, model.VendorIDEBAI)
syncStatus |= model.SyncFlagPriceMask
} else if valid["ebaiCategoryID"] != nil {
vendorIDs = append(vendorIDs, model.VendorIDEBAI)
}
if valid["mtwmPricePercentage"] != nil {
vendorIDs = append(vendorIDs, model.VendorIDMTWM)
syncStatus |= model.SyncFlagPriceMask
} else if valid["mtwmCategoryID"] != nil {
vendorIDs = append(vendorIDs, model.VendorIDMTWM)
}
if len(vendorIDs) > 0 {
SetStoreSkuSyncStatus2(db, nil, vendorIDs, skuIDs, syncStatus)
}
}
}
_, err = CurVendorSync.SyncCategory(ctx, db, categoryID, false, userName)
if len(skuIDs) > 0 {
CurVendorSync.SyncSkus(ctx, db, nil, skuIDs, true, true, userName)
}
}
return num, err
}
func SetStoreCategorySyncStatus2(db *dao.DaoDB, storeIDs []int, catIDs []int, syncStatus int) (num int64, err error) {
for _, vendorID := range partner.GetSingleStoreVendorIDs() {
num2, err2 := dao.SetStoreCategorySyncStatus(db, vendorID, storeIDs, catIDs, syncStatus)
if err = err2; err != nil {
return 0, err
}
num += num2
}
return num, nil
}
func ReorderCategories(ctx *jxcontext.Context, parentID int, categoryIDs []int, userName string, isExd bool) (err error) {
var cats []*model.SkuCategory
db := dao.GetDB()
if err = dao.GetEntitiesByKV(db, &cats, utils.Params2Map(model.FieldParentID, parentID), false); err == nil {
catsLen := len(cats)
if !isExd {
for _, v := range cats {
if v.IsExdSpec == 1 {
catsLen--
}
}
}
if catsLen != len(categoryIDs) {
return ErrInputCatsDoesntMatch
}
catsMap := make(map[int]*model.SkuCategory, catsLen)
for _, cat := range cats {
catsMap[cat.ID] = cat
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
for k, v := range categoryIDs {
if catsMap[v] == nil {
dao.Rollback(db)
return fmt.Errorf("分类:%d不在%d分类下", v, parentID)
}
if isExd {
catsMap[v].ExdSeq = k
} else {
catsMap[v].Seq = k
}
catsMap[v].LastOperator = ctx.GetUserName()
if _, err = dao.UpdateEntity(db, catsMap[v]); err != nil {
dao.Rollback(db)
return err
}
if catsMap[v].IsExdSpec == model.NO {
if err = OnUpdateThing(ctx, db, nil, int64(catsMap[v].ID), model.ThingTypeCategory); err != nil {
dao.Rollback(db)
return err
}
}
}
dao.Commit(db)
SetStoreCategorySyncStatus2(db, nil, categoryIDs, model.SyncFlagModifiedMask)
if err == nil {
_, err = CurVendorSync.SyncReorderCategories(ctx, db, parentID, false, userName)
CurVendorSync.SyncStoresCategory(ctx, db, nil, nil, false, true, true)
}
}
return err
}
func DeleteCategory(ctx *jxcontext.Context, categoryID int, userName string) (num int64, err error) {
cat := &model.SkuCategory{}
cat.ID = categoryID
var countInfos []*struct{ Ct int }
db := dao.GetDB()
if err = dao.GetRows(db, &countInfos, `
SELECT COUNT(*) ct
FROM sku t1
WHERE t1.category_id = ? AND t1.deleted_at = ?
UNION ALL
SELECT COUNT(*) ct
FROM sku_name t1
WHERE t1.category_id = ? AND t1.deleted_at = ?
UNION ALL
SELECT COUNT(*) ct
FROM sku_category t1
WHERE t1.parent_id = ? AND t1.deleted_at = ?
`, categoryID, utils.DefaultTimeValue, categoryID, utils.DefaultTimeValue, categoryID, utils.DefaultTimeValue, &countInfos); err == nil {
if countInfos[0].Ct != 0 {
return 0, errors.New("还有商品使用此类别,不能删除")
} else if countInfos[1].Ct != 0 {
return 0, errors.New("还有商品名使用此类别,不能删除")
} else if countInfos[2].Ct != 0 {
return 0, errors.New("还有商品类别使用此类别,不能删除")
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if _, err = DeleteCategoryMap(ctx, db, categoryID); err != nil {
dao.Rollback(db)
return 0, err
}
if err = OnDeleteThing(ctx, db, nil, int64(categoryID), model.ThingTypeCategory); err != nil {
dao.Rollback(db)
return 0, err
}
if num, err = dao.DeleteEntityLogically(db, cat, map[string]interface{}{
// model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
model.FieldStatus: 0,
}, userName, nil); err != nil {
dao.Rollback(db)
return 0, err
}
dao.Commit(db)
_, err = CurVendorSync.SyncCategory(ctx, db, cat.ID, false, userName)
}
return num, err
}
func DeleteCategoryMap(ctx *jxcontext.Context, db *dao.DaoDB, categoryID int) (num int64, err error) {
if db == nil {
db = dao.GetDB()
}
catMap := &model.StoreSkuCategoryMap{}
return dao.DeleteEntityLogically(db, catMap, map[string]interface{}{
model.FieldEbaiSyncStatus: model.SyncFlagDeletedMask,
model.FieldMtwmSyncStatus: model.SyncFlagDeletedMask,
}, ctx.GetUserName(), map[string]interface{}{
model.FieldCategoryID: categoryID,
model.FieldDeletedAt: utils.DefaultTimeValue,
})
}
func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku, isQueryMidPrice bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *SkuNamesInfo, err error) {
db := dao.GetDB()
sql := `
FROM sku_name t1
LEFT JOIN sku t2 ON t1.id = t2.name_id AND t2.deleted_at = ?
LEFT JOIN sku_name_place_bind t3 ON t1.id = t3.name_id
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if isQueryMidPrice {
sql += ` LEFT JOIN price_refer_snapshot t4 ON t4.city_code = ? AND t4.snapshot_at = ? AND t4.name_id = t1.id`
sqlParams = append(sqlParams, 0, utils.Time2Date(time.Now().AddDate(0, 0, -1)))
}
sql += " WHERE t1.deleted_at = ?"
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += `
AND (t1.name LIKE ? OR t1.prefix LIKE ? OR t2.comment LIKE ? OR t1.upc LIKE ?
OR (SELECT COUNT(*) FROM thing_map tm WHERE tm.vendor_thing_id LIKE ? AND tm.thing_type = ? AND tm.thing_id = t2.id AND tm.deleted_at = ?) > 0`
sqlParams = append(sqlParams,
keywordLike, keywordLike, keywordLike, keywordLike,
keywordLike, model.ThingTypeSku, utils.DefaultTimeValue)
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
sql += " OR t1.id = ? OR t2.id = ? OR t1.category_id = ?"
sqlParams = append(sqlParams, keywordInt64, keywordInt64, keywordInt64)
}
sql += ")"
}
if params["isSpu"] != nil {
sql += " AND t1.is_spu = ?"
sqlParams = append(sqlParams, utils.Bool2Int(params["isSpu"].(bool)))
}
if params["nameID"] != nil {
sql += " AND t1.id = ?"
sqlParams = append(sqlParams, params["nameID"].(int))
}
if params["nameIDs"] != nil {
var nameIDs []int
if ids, ok := params["nameIDs"].([]int); ok {
nameIDs = ids
} else {
if err = utils.UnmarshalUseNumber([]byte(params["nameIDs"].(string)), &nameIDs); err != nil {
return nil, err
}
}
if len(nameIDs) > 0 {
sql += " AND t1.id IN (" + dao.GenQuestionMarks(len(nameIDs)) + ")"
sqlParams = append(sqlParams, nameIDs)
}
}
if params["isExd"] != nil {
var idExd = params["isExd"].(bool)
if idExd {
sql += " AND t2.exd_sku_id <> ''"
} else {
sql += " AND t2.exd_sku_id = ''"
}
} else {
sql += " AND t2.exd_sku_id = ''"
}
if params["categoryID"] != nil {
cat := &model.SkuCategory{}
cat.ID = params["categoryID"].(int)
if err = dao.GetEntity(db, cat); err != nil {
return nil, err
}
sql += " AND (t1.category_id = ?"
sqlParams = append(sqlParams, cat.ID)
if cat.Level == 1 {
sql += " OR t1.category_id IN (SELECT id FROM sku_category WHERE parent_id = ?)"
sqlParams = append(sqlParams, cat.ID)
}
sql += ")"
}
if params["skuCategoryID"] != nil {
cat := &model.SkuCategory{}
cat.ID = params["skuCategoryID"].(int)
if err = dao.GetEntity(db, cat); err != nil {
return nil, err
}
sql += " AND (t2.category_id = ?"
sqlParams = append(sqlParams, cat.ID)
if cat.Level == 1 {
sql += " OR t2.category_id IN (SELECT id FROM sku_category WHERE parent_id = ?)"
sqlParams = append(sqlParams, cat.ID)
}
sql += ")"
}
if params["vendorSkuIDs"] != nil {
var vendorSkuIDs []int
if err = utils.UnmarshalUseNumber([]byte(params["vendorSkuIDs"].(string)), &vendorSkuIDs); err != nil {
return nil, err
}
if len(vendorSkuIDs) > 0 {
sql += " AND (SELECT COUNT(*) FROM thing_map tm WHERE tm.thing_type = ? AND tm.thing_id = t2.id AND tm.deleted_at = ? AND tm.vendor_thing_id IN (" + dao.GenQuestionMarks(len(vendorSkuIDs)) + ")) > 0"
sqlParams = append(sqlParams, utils.DefaultTimeValue, vendorSkuIDs)
}
}
if params["name"] != nil {
sql += " AND t1.name LIKE ?"
sqlParams = append(sqlParams, "%"+params["name"].(string)+"%")
}
if params["prefix"] != nil {
sql += " AND t1.prefix LIKE ?"
sqlParams = append(sqlParams, "%"+params["prefix"].(string)+"%")
}
if params["unit"] != nil {
sql += " AND t1.unit = ?"
sqlParams = append(sqlParams, params["unit"].(string))
}
if placeCond := strings.ToUpper(utils.Interface2String(params["placeCond"])); placeCond == "AND" || placeCond == "OR" {
sqlPlaceCond := ""
if placeCond == "AND" {
sqlPlaceCond += " AND ( 1 = 1"
} else {
sqlPlaceCond += " AND ( 1 = 0"
}
if params["placeCode"] != nil {
sqlPlaceCond += " " + placeCond + " t3.place_code = ?"
sqlParams = append(sqlParams, params["placeCode"].(int))
}
if params["isGlobal"] != nil {
if params["isGlobal"].(bool) {
sqlPlaceCond += " " + placeCond + " t1.is_global = 1"
} else {
sqlPlaceCond += " " + placeCond + " t1.is_global = 0"
}
}
if sqlPlaceCond != " AND ( 1 = 0" {
sql += sqlPlaceCond + ")"
}
}
if params["skuID"] != nil {
sql += " AND t2.id = ?"
sqlParams = append(sqlParams, params["skuID"].(int))
}
if params["skuIDs"] != nil {
var skuIDs []int
if err = utils.UnmarshalUseNumber([]byte(params["skuIDs"].(string)), &skuIDs); err != nil {
return nil, err
}
if len(skuIDs) > 0 {
sql += " AND t2.id IN (" + dao.GenQuestionMarks(len(skuIDs)) + ")"
sqlParams = append(sqlParams, skuIDs)
}
}
if params["fromStatus"] != nil {
fromStatus := params["fromStatus"].(int)
toStatus := fromStatus
if params["toStatus"] != nil {
toStatus = params["toStatus"].(int)
}
sql += " AND t2.status >= ? AND t2.status <= ?"
sqlParams = append(sqlParams, fromStatus, toStatus)
}
sql += `
GROUP BY
t1.id,
t1.created_at,
t1.updated_at,
t1.last_operator,
t1.deleted_at,
t1.prefix,
t1.name,
t1.brand_id,
t1.category_id,
t1.jd_category_id,
t1.is_global,
t1.unit,
t1.price,
t1.img,
t1.img2,
t1.status,
t1.is_spu,
t1.desc_img,
t1.upc,
t1.ex_prefix,
t1.ex_prefix_begin,
t1.ex_prefix_end,
t1.yb_name_suffix
`
if isQueryMidPrice {
sql += `,
t4.mid_unit_price`
}
if isBySku {
sql += `,
t2.id`
}
sqlData := `
SELECT
SQL_CALC_FOUND_ROWS
t1.id,
t1.created_at,
t1.updated_at,
t1.last_operator,
t1.deleted_at,
t1.prefix,
t1.name,
t1.brand_id,
t1.category_id,
t1.jd_category_id,
t1.is_global,
t1.unit,
t1.price,
t1.img,
t1.img2,
t1.status,
t1.is_spu,
t1.desc_img,
t1.upc,
/*
t1.jd_id,
t1.jd_sync_status,
*/
t1.ex_prefix,
t1.ex_prefix_begin,
t1.ex_prefix_end,
t1.yb_name_suffix,
`
if isQueryMidPrice {
sqlData += " t4.mid_unit_price,"
}
sqlData +=
`
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"id":', t2.id, ',"comment":"', t2.comment, '","status":', t2.status,
',"createdAt":"', CONCAT(REPLACE(t2.created_at," ","T"),"+08:00"), '","updatedAt":"', CONCAT(REPLACE(t2.updated_at," ","T"),"+08:00"),
'","lastOperator":"', t2.last_operator, '","specQuality":', t2.spec_quality, ',"specUnit":"', t2.spec_unit,
'","exdSkuID":"', t2.exd_sku_id,
'","eclpID":"', t2.eclp_id,
'","weight":', t2.weight, ',"categoryID":', t2.category_id, ',"nameID":', t2.name_id,
', "seq":', t2.seq,
"}")), "]") skus_str,
CONCAT("[", GROUP_CONCAT(DISTINCT t3.place_code), "]") places_str
` + sql + `
ORDER BY MIN(t2.seq), t1.id DESC
LIMIT ? OFFSET ?`
pageSize = jxutils.FormalizePageSize(pageSize)
offset = jxutils.FormalizePageOffset(offset)
sqlParams = append(sqlParams, pageSize, offset)
skuNamesInfo = &SkuNamesInfo{}
dao.Begin(db) // todo 这里用事务的原因是SQL_CALC_FOUND_ROWS会出错
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
// globals.SugarLogger.Debug(sqlData)
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
if err = dao.GetRows(db, &skuNamesInfo.SkuNames, sqlData, sqlParams...); err == nil {
skuNamesInfo.TotalCount = dao.GetLastTotalRowCount(db)
dao.Commit(db)
var skuIDs []int
for _, skuName := range skuNamesInfo.SkuNames {
skuName.FullName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, "", "", 0, "", 0, skuName.ExPrefix, skuName.ExPrefixBegin, skuName.ExPrefixEnd)
if skuName.SkusStr != "" {
if err = utils.UnmarshalUseNumber([]byte(skuName.SkusStr), &skuName.Skus); err != nil {
dao.Rollback(db)
return nil, err
}
for _, v := range skuName.Skus {
skuIDs = append(skuIDs, v.ID)
}
}
if skuName.PlacesStr != "" {
if err = utils.UnmarshalUseNumber([]byte(skuName.PlacesStr), &skuName.Places); err != nil {
dao.Rollback(db)
return nil, err
}
}
}
if len(skuIDs) > 0 {
thingMapMap, err2 := dao.GetThingMapMap(db, model.ThingTypeSku, nil, skuIDs)
if err = err2; err == nil {
for _, skuName := range skuNamesInfo.SkuNames {
for _, v := range skuName.Skus {
v.MapList = thingMapMap[int64(v.ID)]
}
}
}
}
} else {
dao.Rollback(db)
}
return skuNamesInfo, err
}
func CheckHasSensitiveWord(word string) (bool, error) {
if hasSensitiveWord, sensitiveWord := IsSensitiveWordInList(word); hasSensitiveWord {
return true, errors.New(fmt.Sprintf("不能包含敏感词:[%s]", sensitiveWord))
}
return false, nil
}
func IsSensitiveWordInList(str string) (bool, string) {
wordList, err := dao.GetSensitiveWordList()
if err == nil {
for _, value := range wordList {
keyWord := value.Word
checkHas := strings.Contains(str, keyWord)
if checkHas {
return true, keyWord
}
}
}
return false, ""
}
func AddSkuName(ctx *jxcontext.Context, skuNameExt *model.SkuNameExt, userName string) (outSkuNameExt *model.SkuNameExt, err error) {
if skuNameExt.CategoryID == 0 {
return nil, errors.New("CategoryID不能为空")
}
if len(skuNameExt.Skus) == 0 {
return nil, errors.New("创建SKU NAME时必须至少创建一个SKU")
} else if skuNameExt.Unit != model.SpecialUnit {
if len(skuNameExt.Skus) != 1 {
return nil, errors.New("不为份的SKU NAME只能有一个SKU")
}
}
skuNameExt.Name = utils.TrimBlankChar(skuNameExt.Name)
if hasSensitiveWord, err := CheckHasSensitiveWord(skuNameExt.Name); hasSensitiveWord {
return nil, err
}
upc := utils.Pointer2String(skuNameExt.Upc)
if upc == "" {
skuNameExt.Upc = nil
} else if !jxutils.IsUpcValid(upc) {
return nil, fmt.Errorf("upc:%s不合法请仔细检查", upc)
}
db := dao.GetDB()
skuNameExt.SkuName.Status = model.SkuStatusNormal
if skuNameExt.IsSpu == 1 {
return nil, fmt.Errorf("不允许创建多规格商品")
// skuNameExt.SkuName.JdSyncStatus = model.SyncFlagNewMask
}
if skuNameExt.Unit == model.SpecialUnit {
skuNameExt.SpecQuality = float32(model.SpecialSpecQuality)
skuNameExt.SpecUnit = model.SpecialSpecUnit
} else {
skuNameExt.SpecQuality = skuNameExt.Skus[0].SpecQuality
skuNameExt.SpecUnit = skuNameExt.Skus[0].SpecUnit
}
if skuNameExt.YbNameSuffix == "" {
var name *model.SkuName
sql := "SELECT * FROM sku_name WHERE yb_name_suffix <> '' ORDER BY yb_name_suffix DESC LIMIT 1"
dao.GetRow(db, &name, sql, nil)
if name != nil {
if skuNameExt.Unit == model.UnitNames[0] {
prefix := utils.Int64ToStr(utils.Str2Int64(name.YbNameSuffix) + 1)
realPrefix := prefix
for i := 0; i < 4-len(prefix); i++ {
realPrefix = "0" + realPrefix
}
skuNameExt.YbNameSuffix = realPrefix
if utils.Str2Int64(prefix) > 9999 {
return nil, fmt.Errorf("银豹的商品后缀已超过9999!")
}
}
}
}
picType := true
for _, imgName := range []string{skuNameExt.Img, skuNameExt.Img2} {
if imgName != "" {
dataRes, err2 := datares.TryRegisterDataResource(ctx, skuNameExt.Name, imgName, model.ImgTypeMain, false)
if err = err2; err != nil {
return nil, err
}
if dataRes.ResourceType == model.MimeTypeJpeg || dataRes.ResourceType == model.MimeTypePng {
picType = false
}
}
}
if picType {
return nil, fmt.Errorf("商品图片应至少包含一张非gif格式的图片")
}
if skuNameExt.DescImg != "" {
dataRes, err2 := datares.TryRegisterDataResource(ctx, skuNameExt.Name+"desc", skuNameExt.DescImg, model.ImgTypeDesc, false)
if err = err2; err != nil {
return nil, err
}
if dataRes.ResourceType == model.MimeTypeGif {
return nil, fmt.Errorf("商品详情图片不能上传gif格式的图片")
}
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
dao.WrapAddIDCULDEntity(&skuNameExt.SkuName, userName)
if err = dao.CreateEntity(db, &skuNameExt.SkuName); err != nil {
dao.Rollback(db)
return nil, err
}
if err = OnCreateThing(ctx, db, nil, int64(skuNameExt.SkuName.ID), model.ThingTypeSkuName); err != nil {
dao.Rollback(db)
return nil, err
}
for _, v := range skuNameExt.Skus {
sku := v.Sku
dao.WrapAddIDCULDEntity(sku, userName)
sku.NameID = skuNameExt.ID
// sku.JdSyncStatus = model.SyncFlagNewMask
// sku.JdID = 0
if err = dao.CreateEntity(db, sku); err != nil {
dao.Rollback(db)
return nil, err
}
if sku.EclpID == "" {
if err = OnCreateThing(ctx, db, nil, int64(sku.ID), model.ThingTypeSku); err != nil {
dao.Rollback(db)
return nil, err
}
}
}
for _, placeCode := range skuNameExt.Places {
placeBind := &model.SkuNamePlaceBind{}
dao.WrapAddIDCULEntity(placeBind, userName)
placeBind.NameID = skuNameExt.ID
placeBind.PlaceCode = placeCode
if err = dao.CreateEntity(db, placeBind); err != nil {
dao.Rollback(db)
return nil, err
}
}
dao.Commit(db)
tmpInfo, err := GetSkuNames(ctx, "", false, false, utils.Params2Map("nameID", skuNameExt.SkuName.ID), 0, 1)
if err != nil {
return nil, err
}
if tmpInfo.TotalCount != 1 {
return nil, ErrEntityNotExist
}
outSkuNameExt = tmpInfo.SkuNames[0]
_, err = CurVendorSync.SyncSku(ctx, db, outSkuNameExt.SkuName.ID, -1, false, false, userName)
return outSkuNameExt, err
}
func UpdateSkuName(ctx *jxcontext.Context, nameID int, payload map[string]interface{}, isExd bool) (num int64, err error) {
userName := ctx.GetUserName()
skuName := &model.SkuName{}
skuName.ID = nameID
db := dao.GetDB()
if err = dao.GetEntity(db, skuName); err != nil {
return 0, err
}
var beforSkuName = *skuName
if payload["name"] != nil {
newSkuName := utils.TrimBlankChar(utils.Interface2String(payload["name"]))
if hasSensitiveWord, err := CheckHasSensitiveWord(newSkuName); hasSensitiveWord {
return 0, err
}
payload["name"] = newSkuName
}
delete(payload, "isSpu")
delete(payload, "seq")
valid := dao.StrictMakeMapByStructObject(payload, skuName, userName)
valid = utils.RemoveGeneralMapKeys(valid, model.FieldSpecQuality, model.FieldSpecUnit)
_, hasPlaces := payload["places"]
if len(valid) > 0 || hasPlaces {
if valid["Upc"] != nil {
if upc, _ := valid["Upc"].(string); upc == "" {
valid["Upc"] = nil
} else if !jxutils.IsUpcValid(upc) {
return 0, fmt.Errorf("upc:%s不合法请仔细检查", upc)
}
}
globals.SugarLogger.Debugf("UpdateSkuName valid:%s", utils.Format4Output(valid, false))
for _, imgName := range []string{"img", "img2"} {
if valid[imgName] != nil {
if imgStr := utils.Interface2String(valid[imgName]); imgStr != "" {
_, err2 := datares.TryRegisterDataResource(ctx, skuName.Name, valid[imgName].(string), model.ImgTypeMain, true)
if err = err2; err != nil {
return 0, err
}
}
}
}
if valid["descImg"] != nil {
descImg := valid["descImg"].(string)
if descImg != "" {
_, err2 := datares.TryRegisterDataResource(ctx, skuName.Name+"_desc", descImg, model.ImgTypeDesc, false)
if err = err2; err != nil {
return 0, err
}
}
}
var eclpID string
if payload["eclpID"] != nil {
eclpID = payload["eclpID"].(string)
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
// valid[model.FieldJdSyncStatus] = model.SyncFlagModifiedMask | skuName.JdSyncStatus
if num, err = dao.UpdateEntityLogically(db, skuName, valid, userName, nil); err != nil {
dao.Rollback(db)
return 0, err
}
if !isExd && eclpID == "" {
if err = OnUpdateThing(ctx, db, nil, int64(nameID), model.ThingTypeSkuName); err != nil {
dao.Rollback(db)
return 0, err
}
}
if utils.Interface2Int64WithDefault(payload["isGlobal"], 0) == 0 && payload["places"] != nil {
if places, ok := payload["places"].([]interface{}); ok {
if _, err = dao.DeleteSkuNamePlace(db, nameID, nil); err != nil {
dao.Rollback(db)
return 0, err
}
for _, placeCode := range places {
placeBind := &model.SkuNamePlaceBind{}
placeBind.PlaceCode = int(utils.Interface2Int64WithDefault(placeCode, 0))
if placeBind.PlaceCode > 0 {
dao.WrapAddIDCULEntity(placeBind, userName)
placeBind.NameID = nameID
err = dao.CreateEntity(db, placeBind)
} else {
dao.Rollback(db)
return 0, errors.New("地点代码非法")
}
}
}
}
skuList, err2 := dao.GetSkus(db, nil, []int{nameID}, nil, nil, nil)
if err = err2; err == nil {
for _, v := range skuList {
sku := &v.Sku
// sku.JdSyncStatus |= model.SyncFlagModifiedMask
sku.LastOperator = userName
sku.UpdatedAt = time.Now()
if _, err = dao.UpdateEntity(db, sku); err != nil {
dao.Rollback(db)
return 0, err
}
if sku.ExdSkuID == "" && sku.EclpID == "" {
if err = OnUpdateThing(ctx, db, nil, int64(v.ID), model.ThingTypeSku); err != nil {
dao.Rollback(db)
return 0, err
}
}
}
}
skuIDs, err2 := dao.GetSkuIDByNames(db, []int{nameID})
if err = err2; err != nil {
dao.Rollback(db)
return 0, err
}
if len(skuIDs) > 0 {
if _, err = SetStoreSkuSyncStatus2(db, nil, partner.GetSingleStoreVendorIDs(), skuIDs, model.SyncFlagModifiedMask); err != nil {
dao.Rollback(db)
return 0, err
}
}
dao.Commit(db)
errList := errlist.New()
errList.AddErr(err)
_, err = CurVendorSync.SyncSku(ctx, db, nameID, -1, false, false, userName)
errList.AddErr(err)
err = errList.GetErrListAsOne()
if globals.IsAddEvent {
mapBefore := refutil.FindMapAndStructMixed(valid, beforSkuName)
err = AddEventDetail(db, ctx, model.OperateUpdate, nameID, model.ThingTypeSkuName, 0, BuildDiffData(mapBefore), BuildDiffData(valid))
}
}
return num, err
}
func SetStoreSkuSyncStatus2(db *dao.DaoDB, storeIDs []int, vendorIDs, skuIDs []int, syncStatus int) (num int64, err error) {
for _, vendorID := range vendorIDs {
num2, err2 := dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, skuIDs, syncStatus)
if err = err2; err != nil {
return 0, err
}
num += num2
}
return num, nil
}
func DeleteSkuName(ctx *jxcontext.Context, nameID int, userName string) (num int64, err error) {
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if _, err := dao.DeleteSkuNamePlace(db, nameID, nil); err != nil {
dao.Rollback(db)
return 0, err
}
if _, err = DeleteStoreSku(ctx, db, nameID, 0); err != nil {
dao.Rollback(db)
return 0, err
}
skuList, err2 := dao.GetSkus(db, nil, []int{nameID}, nil, nil, nil)
if err = err2; err == nil {
for _, v := range skuList {
sku := &v.Sku
if err = OnDeleteThing(ctx, db, nil, int64(v.ID), model.ThingTypeSku); err != nil {
dao.Rollback(db)
return 0, err
}
if _, err = dao.DeleteEntityLogically(db, sku, map[string]interface{}{
// model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
model.FieldStatus: model.SkuStatusDeleted,
}, userName, nil); err != nil {
dao.Rollback(db)
return 0, err
}
}
}
if err = OnDeleteThing(ctx, db, nil, int64(nameID), model.ThingTypeSkuName); err != nil {
dao.Rollback(db)
return 0, err
}
skuName := &model.SkuName{}
skuName.ID = nameID
if num, err = dao.DeleteEntityLogically(db, skuName, map[string]interface{}{
// model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
model.FieldStatus: model.SkuStatusDeleted,
}, userName, nil); err != nil {
dao.Rollback(db)
return 0, err
}
dao.Commit(db)
if len(skuList) > 0 {
_, err = CurVendorSync.SyncSku(ctx, db, skuName.ID, -1, false, false, userName)
}
return num, err
}
func AddSku(ctx *jxcontext.Context, nameID int, sku *model.Sku, userName string) (outSkuNameExt *model.SkuNameExt, err error) {
db := dao.GetDB()
skuName := &model.SkuName{}
skuName.ID = nameID
if err = dao.GetEntity(db, skuName); err != nil {
return nil, err
}
if skuName.Unit != model.SpecialUnit {
return nil, errors.New("不为份的SKU NAME只能有一个SKU")
}
dao.WrapAddIDCULDEntity(sku, userName)
// sku.JdSyncStatus = model.SyncFlagNewMask
// sku.JdID = 0
sku.NameID = nameID
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if err = dao.CreateEntity(db, sku); err != nil {
dao.Rollback(db)
return nil, err
}
if err = OnCreateThing(ctx, db, nil, int64(sku.ID), model.ThingTypeSku); err != nil {
dao.Rollback(db)
return nil, err
}
dao.Commit(db)
result, err2 := GetSkuNames(ctx, "", false, false, utils.Params2Map("skuID", sku.ID), 0, 0)
if err = err2; err == nil {
if result.TotalCount == 1 {
outSkuNameExt = result.SkuNames[0]
_, err = CurVendorSync.SyncSku(ctx, db, outSkuNameExt.SkuName.ID, sku.ID, false, false, userName)
} else {
err = ErrEntityNotExist
}
}
return outSkuNameExt, err
}
func UpdateSku(ctx *jxcontext.Context, skuID int, payload map[string]interface{}) (num int64, err error) {
userName := ctx.GetUserName()
sku := &model.Sku{}
sku.ID = skuID
db := dao.GetDB()
if err = dao.GetEntity(db, sku); err != nil {
return 0, err
}
var beforSku = *sku
valid := dao.StrictMakeMapByStructObject(payload, sku, userName)
if len(valid) > 0 {
// globals.SugarLogger.Debug(utils.Format4Output(valid, false))
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
maskValue := int8(model.SyncFlagModifiedMask)
if valid["specQuality"] != nil || valid["specUnit"] != nil {
maskValue |= model.SyncFlagSpecMask
}
// valid[model.FieldJdSyncStatus] = maskValue | sku.JdSyncStatus
if num, err = dao.UpdateEntityLogically(db, sku, valid, userName, nil); err != nil || num == 0 {
dao.Rollback(db)
if err == nil {
err = ErrEntityNotExist
}
return 0, err
}
if _, err = dao.ExecuteSQL(db, `
UPDATE sku_name t1
JOIN sku t2 ON t1.id = t2.name_id
SET t1.spec_quality = t2.spec_quality,
t1.spec_unit = t2.spec_unit
WHERE t1.deleted_at = ? AND t2.id = ? AND t1.unit <> ?
`, utils.DefaultTimeValue, skuID, model.SpecialUnit); err != nil {
dao.Rollback(db)
if err == nil {
err = ErrEntityNotExist
}
return 0, err
}
if sku.ExdSkuID == "" && sku.EclpID == "" {
if err = OnUpdateThing(ctx, db, nil, int64(skuID), model.ThingTypeSku); err != nil {
dao.Rollback(db)
return 0, err
}
}
dao.Commit(db)
if _, err = SetStoreSkuSyncStatus2(db, nil, partner.GetSingleStoreVendorIDs(), []int{skuID}, model.SyncFlagModifiedMask); err == nil {
if maskValue&model.SyncFlagSpecMask != 0 {
err = refreshStoreSkuPrice(ctx, db, skuID)
}
}
errList := errlist.New()
errList.AddErr(err)
_, err = CurVendorSync.SyncSku(ctx, db, -1, sku.ID, false, false, userName)
errList.AddErr(err)
err = errList.GetErrListAsOne()
if globals.IsAddEvent {
mapBefore := refutil.FindMapAndStructMixed(valid, beforSku)
err = AddEventDetail(db, ctx, model.OperateUpdate, skuID, model.ThingTypeSku, 0, BuildDiffData(mapBefore), BuildDiffData(valid))
}
}
return num, err
}
func refreshStoreSkuPrice(ctx *jxcontext.Context, db *dao.DaoDB, skuID int) (err error) {
list, err := dao.GetStoreSkusAndSkuName(db, nil, []int{skuID}, nil)
task := tasksch.NewParallelTask("refreshStoreSkuPrice", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
v := batchItemList[0].(*dao.StoreSkuAndName)
storeID := v.StoreID
storeDetail, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX)
if storeDetail == nil {
return retVal, err
}
storeSku := &model.StoreSkuBind{}
storeSku.ID = v.BindID
storeSku.JdSyncStatus = v.JdSyncStatus | model.SyncFlagPriceMask
storeSku.MtwmSyncStatus = v.MtwmSyncStatus | model.SyncFlagPriceMask
storeSku.EbaiSyncStatus = v.EbaiSyncStatus | model.SyncFlagPriceMask
storeSku.Price = jxutils.CaculateSkuPrice(int(v.UnitPrice), v.SpecQuality, v.SpecUnit, v.Unit)
storeSku.JxPrice = jxutils.CaculatePriceByPricePack(storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage), int(storeSku.Price))
storeSku.LastOperator = ctx.GetUserName()
storeSku.UpdatedAt = time.Now()
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
dao.UpdateEntity(db, storeSku, "Price", "JdSyncStatus", "MtwmSyncStatus", "EbaiSyncStatus", "JxPrice", "LastOperator")
dao.Commit(db)
return retVal, err
}, list)
tasksch.HandleTask(task, nil, true).Run()
_, err = task.GetResult(0)
return err
}
func DeleteSku(ctx *jxcontext.Context, skuID int, userName string) (num int64, err error) {
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if _, err = DeleteStoreSku(ctx, db, 0, skuID); err != nil {
dao.Rollback(db)
return 0, err
}
if err = OnDeleteThing(ctx, db, nil, int64(skuID), model.ThingTypeSku); err != nil {
dao.Rollback(db)
return 0, err
}
sku := &model.Sku{}
sku.ID = skuID
if num, err = dao.DeleteEntityLogically(db, sku, map[string]interface{}{
model.FieldStatus: model.SkuStatusDeleted,
// model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
}, userName, nil); err != nil {
dao.Rollback(db)
return 0, err
}
dao.Commit(db)
if num == 1 {
_, err = CurVendorSync.SyncSku(ctx, db, -1, sku.ID, false, false, userName)
}
return num, err
}
func DeleteStoreSku(ctx *jxcontext.Context, db *dao.DaoDB, nameID, skuID int) (num int64, err error) {
if db == nil {
db = dao.GetDB()
}
sql := `
SELECT *
FROM sku t1
WHERE 1 = 1
`
sqlParams := []interface{}{}
if nameID > 0 {
sql += " AND t1.name_id = ?"
sqlParams = append(sqlParams, nameID)
} else {
sql += " AND t1.id = ?"
sqlParams = append(sqlParams, skuID)
}
var skuList []*model.Sku
if err = dao.GetRows(db, &skuList, sql, sqlParams); err == nil {
num = int64(len(skuList))
for _, v := range skuList {
storeSkuBind := &model.StoreSkuBind{}
_, err = dao.DeleteEntityLogically(db, storeSkuBind, map[string]interface{}{
model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
model.FieldMtwmSyncStatus: model.SyncFlagDeletedMask,
model.FieldEbaiSyncStatus: model.SyncFlagDeletedMask,
}, ctx.GetUserName(), map[string]interface{}{
model.FieldSkuID: v.ID,
model.FieldDeletedAt: utils.DefaultTimeValue,
})
if err != nil {
break
}
}
}
return num, err
}
func AddSkuNamePlace(ctx *jxcontext.Context, nameID, placeCode int, userName string) (outPlaceBind *model.SkuNamePlaceBind, err error) {
db := dao.GetDB()
placeBind := &model.SkuNamePlaceBind{
NameID: nameID,
PlaceCode: placeCode,
}
dao.WrapAddIDCULEntity(placeBind, userName)
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if err = dao.CreateEntity(db, placeBind); err != nil {
dao.Rollback(db)
return nil, err
}
if err = OnUpdateThing(ctx, db, nil, int64(nameID), model.ThingTypeSkuName); err != nil {
dao.Rollback(db)
return nil, err
}
dao.Commit(db)
_, err = CurVendorSync.SyncSku(ctx, db, nameID, -1, false, false, userName)
return placeBind, err
}
func DeleteSkuNamePlace(ctx *jxcontext.Context, nameID, placeCode int, userName string) (num int64, err error) {
db := dao.GetDB()
placeBind := &model.SkuNamePlaceBind{}
placeBind.NameID = nameID
placeBind.PlaceCode = placeCode
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if num, err = dao.DeleteEntity(db, placeBind, model.FieldNameID, model.FieldPlaceCode); err != nil || num == 0 {
dao.Rollback(db)
if err == nil {
err = ErrEntityNotExist
}
return 0, err
}
if err = OnUpdateThing(ctx, db, nil, int64(nameID), model.ThingTypeSkuName); err != nil {
dao.Rollback(db)
return 0, err
}
dao.Commit(db)
_, err = CurVendorSync.SyncSku(ctx, db, nameID, -1, false, false, userName)
return num, err
}
// func GetVendorSku(ctx *jxcontext.Context, vendorID int, vendorOrgCode, vendorSkuID string) (skuNameInfo *model.SkuNameExt, err error) {
// if handler := CurVendorSync.GetMultiStoreHandler(vendorID); handler != nil {
// return handler.ReadSku(ctx, vendorOrgCode, vendorSkuID)
// }
// return nil, ErrCanNotFindVendor
// }
func SortCategorySkus(ctx *jxcontext.Context, catID int, skuIDList []int) (err error) {
db := dao.GetDB()
userName := ctx.GetUserName()
var skuList []*model.Sku
if skuList, err = dao.GetSkuByCats(db, []int{catID}); err == nil && len(skuList) > 0 {
if len(skuList) != len(skuIDList) {
return errors.New("商品数量不匹配!")
}
skuIDMap := make(map[int]int)
for index, id := range skuIDList {
skuIDMap[id] = index + 1
}
for _, value := range skuList {
if _, ok := skuIDMap[value.ID]; !ok {
return errors.New("商品数据不匹配!")
}
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
nameIDList := []int{}
for _, value := range skuList {
seq := skuIDMap[value.ID]
if value.Seq != seq {
kvs := map[string]interface{}{
model.FieldSkuSeq: seq,
//model.FieldJdSyncStatus: (value.JdSyncStatus | model.SyncFlagModifiedMask),
}
dao.UpdateEntityLogically(db, value, kvs, userName, nil)
nameIDList = append(nameIDList, value.NameID)
}
}
//_, err = CurVendorSync.SyncSkus(ctx, db, nameIDList, []int{}, false, false, userName)
if err == nil && len(nameIDList) > 0 {
dao.Commit(db)
skuIDs, err2 := dao.GetSkuIDByNames(db, nameIDList)
if err = err2; err == nil && len(skuIDs) > 0 {
_, err = SetStoreSkuSyncStatus2(db, nil, partner.GetSingleStoreVendorIDs(), skuIDs, model.SyncFlagModifiedMask)
}
} else {
dao.Rollback(db)
}
}
return err
}
func GetJdUpcCodeByCode(ctx *jxcontext.Context, upcCode string) (productInfos []*jdapi.ProductInfo, err error) {
productInfo, err := api.JdAPI.GetJdUpcCodeByName("", upcCode, 1, 30)
if err != nil {
return nil, err
}
for _, v := range productInfo {
_, name, _, specUnit, unit, specQuality := jxutils.SplitSkuName(v.OriginalName)
v.Name = name
v.SpecQuality = specQuality
v.SpecUnit = specUnit
v.Unit = unit
}
return productInfo, err
}
func GetJdUpcCodeByName(ctx *jxcontext.Context, name, upcCode string) (productInfos []*jdapi.ProductInfo, err error) {
if name != "" {
var (
pageNo = 5
pageSize = 30
pageNoList []int
)
if name == "" && upcCode == "" {
return nil, fmt.Errorf("至少输入一个条件查询商品名或者upc码")
}
for i := 1; i < pageNo+1; i++ {
pageNoList = append(pageNoList, i)
}
task := tasksch.NewParallelTask("获取京东商品", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
pageNum := batchItemList[0].(int)
productInfo, err := api.JdAPI.GetJdUpcCodeByName(name, upcCode, pageNum, pageSize)
if err != nil {
return retVal, err
}
for _, v := range productInfo {
_, name, _, specUnit, unit, specQuality := jxutils.SplitSkuName(v.OriginalName)
v.Name = name
v.SpecQuality = specQuality
v.SpecUnit = specUnit
v.Unit = unit
}
retVal = productInfo
return retVal, err
}, pageNoList)
tasksch.HandleTask(task, nil, true).Run()
productInfoInterface, err2 := task.GetResult(0)
err = err2
for _, v := range productInfoInterface {
productInfos = append(productInfos, v.(*jdapi.ProductInfo))
}
} else {
productInfos, err = GetJdUpcCodeByCode(ctx, upcCode)
}
return productInfos, err
}
func UpdateSkuNamesExPrefix(ctx *jxcontext.Context, nameIDs []int, exPrefix, fromTime, toTime string, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
fromTimeP time.Time
toTimeP time.Time
db = dao.GetDB()
)
if fromTime != "" {
fromTimeP = utils.Time2Date(utils.Str2Time(fromTime))
}
if toTime != "" {
toTimeP = utils.Time2Date(utils.Str2Time(toTime))
}
if toTimeP.Before(fromTimeP) {
return "", fmt.Errorf("结束时间不可以小于开始时间!开始时间:[%v],结束时间:[%v]", fromTimeP, toTimeP)
}
task := tasksch.NewParallelTask("批量设置商品前缀", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
now := utils.Time2Date(time.Now())
switch step {
case 0:
task := tasksch.NewParallelTask("批量设置商品前缀", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
nameID := batchItemList[0].(int)
payload := map[string]interface{}{
"exPrefix": exPrefix,
"exPrefixBegin": fromTimeP,
"exPrefixEnd": toTimeP,
}
if now.Sub(toTimeP) <= 0 && now.Sub(fromTimeP) >= 0 {
_, err = UpdateSkuName(ctx, nameID, payload, false)
} else if now.Sub(fromTimeP) > 0 && now.Sub(toTimeP) > 0 {
payload["exPrefixBegin"] = nil
payload["exPrefixEnd"] = nil
_, err = UpdateSkuName(ctx, nameID, payload, false)
} else {
skuList, err := dao.GetSkus(db, nil, []int{nameID}, nil, nil, nil)
if err == nil && len(skuList) > 0 {
if skuList[0].ExPrefixBegin != nil {
_, err = UpdateSkuName(ctx, nameID, payload, false)
CurVendorSync.SyncStoresSkus2(ctx, nil, 0, db, partner.GetSingleStoreVendorIDs(), nil, false, []int{skuList[0].ID}, nil, model.SyncFlagModifiedMask, true, true)
} else {
skuName := &model.SkuName{
ExPrefix: exPrefix,
ExPrefixBegin: &fromTimeP,
ExPrefixEnd: &toTimeP,
}
skuName.ID = nameID
skuName.LastOperator = ctx.GetLoginID()
skuName.UpdatedAt = time.Now()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
_, err = dao.UpdateEntity(db, skuName, "ExPrefix", "ExPrefixBegin", "ExPrefixEnd", "LastOperator", "UpdatedAt")
dao.Commit(db)
}
}
}
return retVal, err
}, nameIDs)
tasksch.HandleTask(task, nil, true).Run()
_, err = task.GetResult(0)
case 1:
if (now.Sub(toTimeP) <= 0 && now.Sub(fromTimeP) >= 0) || (now.Sub(fromTimeP) > 0 && now.Sub(toTimeP) > 0) {
var skuIDs []int
skuList, err2 := dao.GetSkus(db, nil, nameIDs, nil, nil, nil)
if err = err2; err == nil {
if len(skuList) > 0 {
for _, v := range skuList {
skuIDs = append(skuIDs, v.ID)
}
CurVendorSync.SyncStoresSkus2(ctx, nil, 0, db, partner.GetSingleStoreVendorIDs(), nil, false, skuIDs, nil, model.SyncFlagModifiedMask, true, true)
}
}
}
}
return retVal, err
}, []int{0, 1})
tasksch.HandleTask(task, nil, true).Run()
if !isAsync {
_, err = task.GetResult(0)
hint = "1"
} else {
hint = task.GetID()
}
return hint, err
}
func SetSingleStoreSkuSyncModifyStatus(db *dao.DaoDB, vendorIDs []int) (err error) {
_, err = dao.UpdateStoreSkuBindSyncStatusForExPrefix(db, vendorIDs)
return err
}
func SetMultiStoreSkuSyncModifyStatus(db *dao.DaoDB, vendorIDs []int) (err error) {
_, err = dao.UpdateSkuSyncStatusForExPrefix(db, vendorIDs)
return err
}
func DeleteSkuNameExPrefixOverdue(db *dao.DaoDB) (err error) {
_, err = dao.DeleteSkuNameExPrefixOverdue(db)
return err
}
func SumExianDaDepot(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
db := dao.GetDB()
results, err := api.EbaiAPI.GetExianDaSkuDepot("")
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
v := batchItemList[0].(*ebaiapi.ExianDaSkus)
skus, err := api.EbaiAPI.GetExianDaSku(utils.Str2Int64(v.ElemeGoodsID))
if err != nil || skus == nil {
globals.SugarLogger.Debugf("GetExianDaSku[%v]", v.ElemeGoodsID)
return result, err
}
// sku := &model.Sku{}
// sku.ExdSkuID = v.ElemeGoodsID
// sku.DeletedAt = utils.DefaultTimeValue
// dao.GetEntity(db, sku, "ExdSkuID","DeletedAt")
skuNameExt := &model.SkuName{}
sql2 := `
SELECT a.*
FROM sku_name a
JOIN sku b ON b.name_id = a.id
WHERE a.upc = ?
AND a.deleted_at = ? AND b.deleted_at = ?
`
sqlParams2 := []interface{}{
skus.UpcIds[0],
utils.DefaultTimeValue, utils.DefaultTimeValue,
}
dao.GetRow(db, skuNameExt, sql2, sqlParams2)
prefix, _, _, specUnit, unit, specQuality := jxutils.SplitSkuName(v.GoodsName)
//京西库中存在此商品
if skuNameExt.ID != 0 {
var flag = false
if skuNameExt.Name != v.GoodsName {
skuNameExt.Name = v.GoodsName
skuNameExt.Prefix = prefix
skuNameExt.SpecUnit = specUnit
skuNameExt.Unit = unit
skuNameExt.SpecQuality = specQuality
flag = true
}
if skuNameExt.Img != v.ImageURL {
skuNameExt.Img = v.ImageURL
flag = true
}
if flag {
_, err = dao.UpdateEntity(db, skuNameExt, "Name", "Prefix", "SpecUnit", "Unit", "SpecQuality", "Img")
if err != nil {
return result, err
}
}
} else {
skuName := &model.SkuName{
Prefix: prefix,
Name: v.GoodsName,
IsGlobal: model.YES,
Unit: unit,
SpecQuality: specQuality,
SpecUnit: specUnit,
Price: 100,
Img: v.ImageURL,
Upc: &v.UpcID,
Status: model.SkuStatusNormal,
}
skuName.CategoryID = model.NoCatCatgoryID //默认给了个分类
dao.WrapAddIDCULDEntity(skuName, ctx.GetUserName())
err = dao.CreateEntity(db, skuName)
if err != nil {
return result, err
}
sku := &model.Sku{
NameID: skuName.ID,
SpecQuality: specQuality,
SpecUnit: specUnit,
Weight: int(utils.Str2Int64(skus.Weight)),
Status: model.SkuStatusNormal,
ExdSkuID: v.ElemeGoodsID,
ExdCategoryThirdID: skus.CategoryIDThird,
}
dao.WrapAddIDCULDEntity(sku, ctx.GetUserName())
err = dao.CreateEntity(db, sku)
if err != nil {
return result, err
}
}
return retVal, err
}
taskParallel := tasksch.NewParallelTask("更新京西上饿鲜达商品库", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, results)
tasksch.HandleTask(taskParallel, task, true).Run()
_, err = taskParallel.GetResult(0)
case 1:
}
return result, err
}
taskSeq := tasksch.NewSeqTask2("合并饿鲜达商品库", ctx, isContinueWhenError, taskSeqFunc, 2)
tasksch.HandleTask(taskSeq, nil, true).Run()
if !isAsync {
_, err = taskSeq.GetResult(0)
hint = "1"
} else {
hint = taskSeq.GetID()
}
return hint, err
}
func UpdateExianDaSkuCategory(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
db = dao.GetDB()
skus []*model.SkuName
)
sql := `
SELECT a.*
FROM sku_name a
JOIN sku b ON b.name_id = a.id
WHERE b.exd_sku_id <> ''
AND a.deleted_at = ?
AND b.deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue, utils.DefaultTimeValue,
}
err = dao.GetRows(db, &skus, sql, sqlParams...)
task := tasksch.NewParallelTask("更新京西上饿鲜达商品分类", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
v := batchItemList[0].(*model.SkuName)
skuList, err := api.Ebai2API.GetEbaiDepotSku(ebaiapi.EbaiWholeCountryStore, *v.Upc)
if err != nil || len(skuList) == 0 || skuList[0] == nil {
return retVal, err
}
sku, err := api.Ebai2API.GetEbaiSku(skuList[0].UpcID, ebaiapi.EbaiWholeCountryStore)
if err != nil || sku == nil || sku.CustomCatName == "" {
return retVal, err
}
skuCat := &model.SkuCategory{}
sql := `
SELECT *
FROM sku_category
WHERE exd_name like ?
`
sqlParams := []interface{}{
"%" + sku.CustomCatName + "%",
}
err = dao.GetRow(db, skuCat, sql, sqlParams)
v.CategoryID = skuCat.ID
_, err = dao.UpdateEntity(db, v, "CategoryID")
if err != nil {
return retVal, err
}
return retVal, err
}, skus)
tasksch.HandleTask(task, nil, true).Run()
if !isAsync {
_, err = task.GetResult(0)
hint = "1"
} else {
hint = task.GetID()
}
return hint, err
}
func SendNoCatSkusToOperater(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
skuNames []*model.SkuName
)
globals.SugarLogger.Debugf("SendNoCatSkusToOperater")
sql := `
SELECT * FROM sku_name WHERE deleted_at = ? AND (category_id = ? OR img = ?) AND unit <> ?
`
sqlParams := []interface{}{utils.DefaultTimeValue, model.NoCatCatgoryID, model.NOSkuNameImg, model.UnitNames[0]}
err = dao.GetRows(db, &skuNames, sql, sqlParams)
if err != nil {
return err
}
if len(skuNames) > 10 {
noticeMsg := "有超过10个标品未进行分类和未设置图片"
for _, v := range skuNames {
noticeMsg += "NameID" + utils.Int2Str(v.ID) + ",商品名:" + v.Name + ""
}
for _, mobile := range sendNoCatSkusMobile {
if user, err := dao.GetUserByID(db, "mobile", mobile); err != nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "标品未分类和未设置图片", noticeMsg)
}
}
}
return err
}
func buildCreateUpcSkuByExcelErr(v *model.SkuName, errMsg string) (createUpcSkuByExcelErr *CreateUpcSkuByExcelErr) {
createUpcSkuByExcelErr = &CreateUpcSkuByExcelErr{
Upc: *v.Upc,
Name: v.Name,
Unit: v.Unit,
SpecQuality: utils.Float64ToStr(float64(v.SpecQuality)),
Price: v.Price / 100,
Err: errMsg,
}
return createUpcSkuByExcelErr
}
func CreateUpcSkuByExcel(ctx *jxcontext.Context, files []*multipart.FileHeader, categoryID int) (hint string, err error) {
if len(files) == 0 {
return "", errors.New("没有文件上传!")
}
fileHeader := files[0]
file, err := fileHeader.Open()
hint, err = CreateUpcSkuByExcelBin(ctx, file, categoryID)
file.Close()
return hint, err
}
func CreateUpcSkuByExcelBin(ctx *jxcontext.Context, reader io.Reader, categoryID int) (hint string, err error) {
var (
db = dao.GetDB()
skuParams []*model.SkuName
createUpcSkuByExcelErrList []*CreateUpcSkuByExcelErr
createUpcSkuByExcelErrListInterface []interface{}
excelTitle = []string{
"商品条码",
"商品名称",
"单位",
"重量(g)",
"售价",
"错误原因",
}
upcRegexp = regexp.MustCompile(`(^\d{12,13}$)`)
)
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result2 interface{}, err error) {
switch step {
case 0:
xlsx, err := excelize.OpenReader(reader)
if err != nil {
return result2, err
}
rows, _ := xlsx.GetRows(xlsx.GetSheetName(1))
for rowNum, row := range rows {
if rowNum < 1 {
continue
}
var (
skuParam = &model.SkuName{}
upc string
unit string
specQuality float32
price int
name string
)
for k, cell := range row {
if cell != "" {
if k == 0 {
upc = cell
}
if k == 1 {
name = cell
}
if k == 2 {
unit = cell
}
if k == 3 {
specQuality = float32(utils.Str2Float64WithDefault(cell, 0))
}
if k == 4 {
price = int(utils.Str2Float64WithDefault(cell, 0) * 100)
}
}
}
skuParam.Upc = &upc
skuParam.Unit = unit
skuParam.SpecQuality = specQuality
skuParam.Price = price
skuParam.Name = name
skuParams = append(skuParams, skuParam)
}
case 1:
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
var (
v = batchItemList[0].(*model.SkuName)
skuNames []model.SkuName
skuName = &model.SkuNameExt{
SkuName: model.SkuName{},
Skus: []*model.SkuWithVendor{
&model.SkuWithVendor{
Sku: &model.Sku{},
},
},
}
)
if v.Upc != nil {
upc := upcRegexp.FindString(*v.Upc)
if upc == "" {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "请输入正确的商品条码!")}
return retVal, err
}
skuName.Upc = v.Upc
} else {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "商品的条码不能为空!")}
return retVal, err
}
sql := `
SELECT * FROM sku_name WHERE upc = ? AND deleted_at = ?
`
sqlParams := []interface{}{*v.Upc, utils.DefaultTimeValue}
err = dao.GetRows(db, &skuNames, sql, sqlParams)
if len(skuNames) > 0 {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "商品在京西库中已存在!")}
return retVal, err
}
productInfos, err := GetJdUpcCodeByCode(ctx, *v.Upc)
if err != nil {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
return retVal, err
}
if len(productInfos) == 0 {
var result *aliupcapi.GetAliUpcInfoResult
upcDepot, err := dao.GetUpcDepot(db, *v.Upc)
if upcDepot == nil {
result, err = api.AliUpcAPI.GetAliUpcInfo(*v.Upc)
if err == nil {
err = dao.InsertUpcDepot(db, result)
}
} else {
result = upcDepot
}
if result == nil {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未在标品库查到此商品,请手动创建!")}
return retVal, err
}
if result.Img != "" {
downloadURL, err := uploadImgStandard(skuName.Img)
if err != nil {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
return retVal, err
}
skuName.Img = downloadURL
// if resBinary, _, err := jxutils.DownloadFileByURL(result.Img); err == nil {
// if downloadURL, err := jxutils.UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix())+"origin"+result.Img[strings.LastIndex(result.Img, "/")+1:len(result.Img)]); err == nil {
// resBinary2, _, err := jxutils.DownloadFileByURL(downloadURL + model.SkuNameImgStandard)
// downloadURL2, err := jxutils.UploadExportContent(resBinary2, utils.Int64ToStr(time.Now().Unix())+downloadURL[strings.LastIndex(downloadURL, "/")+1:len(downloadURL)])
// if err == nil {
// skuName.Img = downloadURL2
// } else {
// retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
// return retVal, err
// }
// } else {
// retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
// return retVal, err
// }
// } else {
// retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
// return retVal, err
// }
} else {
skuName.Img = model.NOSkuNameImg
}
if v.Name != "" {
skuName.Name = v.Name
} else {
skuName.Name = result.GoodsName
}
if v.Price == 0 {
if result.Price == "" {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未查询到商品售价,请补充商品的售价!")}
return retVal, err
} else {
skuName.Price = int(utils.Str2Int64(result.Price) * 100)
}
} else {
skuName.Price = v.Price
}
getNetUpcInfo, err := api.AliUpcAPI.GetNetUpcInfo(*v.Upc)
if v.Unit != "" {
if v.Unit == model.UnitNames[0] {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "标品的单位不能为份!")}
return retVal, err
}
skuName.Unit = v.Unit
} else {
if getNetUpcInfo.Unit != "" {
skuName.Unit = getNetUpcInfo.Unit
} else {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未查询到商品单位,请补充商品单位!")}
return retVal, err
}
}
if v.SpecQuality != 0 {
skuName.Skus[0].SpecQuality = v.SpecQuality
skuName.Skus[0].Weight = utils.Float32ToInt(v.SpecQuality)
skuName.Skus[0].SpecUnit = model.SpecUnitNames[0]
} else {
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(v.Name)
if specQuality != 0 {
skuName.Skus[0].SpecQuality = specQuality
if specUnit == model.SpecUnitNames[1] || specUnit == model.SpecUnitNames[2] {
skuName.Skus[0].Weight = int(utils.Str2Int64(utils.Float64ToStr(float64(specQuality) * 1000)))
} else {
skuName.Skus[0].Weight = utils.Float32ToInt(specQuality)
}
} else {
if getNetUpcInfo.SpecQuality != 0 {
if getNetUpcInfo.SpecUnit == model.SpecUnitNames[1] || getNetUpcInfo.SpecUnit == model.SpecUnitNames[2] ||
getNetUpcInfo.SpecUnit == "KG" || getNetUpcInfo.SpecUnit == "l" {
skuName.Skus[0].Weight = int(utils.Str2Int64(utils.Float64ToStr(float64(getNetUpcInfo.SpecQuality) * 1000)))
} else {
skuName.Skus[0].Weight = utils.Float32ToInt(getNetUpcInfo.SpecQuality)
}
skuName.Skus[0].SpecQuality = getNetUpcInfo.SpecQuality
} else {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未查询到商品重量,请补充商品重量!")}
return retVal, err
}
}
if getNetUpcInfo.SpecUnit != "" {
skuName.Skus[0].SpecUnit = getNetUpcInfo.SpecUnit
} else {
skuName.Skus[0].SpecUnit = model.SpecUnitNames[0]
}
}
} else {
productInfo := productInfos[0]
if productInfo.Name == "" {
if v.Name != "" {
productInfo.Name = v.Name
} else {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "需要填上一个合适的商品名!")}
return retVal, err
}
}
skuNames2, _ := dao.GetSkuNames(db, nil, nil, productInfo.Name, false)
if len(skuNames2) > 1 {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "此商品名在京西库中查询出了大于1个商品")}
return retVal, err
}
//表示查到了需要把upc更新上去没查到就要新建
if len(skuNames2) == 1 && (productInfo.SpecQuality == skuNames2[0].SpecQuality && productInfo.SpecUnit == skuNames2[0].SpecUnit) {
skuNames2[0].Upc = v.Upc
dao.UpdateEntity(db, skuNames2[0], "Upc")
return retVal, err
} else {
if v.Price == 0 {
result, err := api.AliUpcAPI.GetAliUpcInfo(*v.Upc)
if err != nil {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
return retVal, err
}
if result.Price == "" {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未查询到商品售价,请补充商品售价!")}
return retVal, err
} else {
skuName.Price = int(utils.Str2Int64(result.Price) * 100)
}
} else {
skuName.Price = v.Price
}
skuName.Name = productInfo.Name
getNetUpcInfo, err := api.AliUpcAPI.GetNetUpcInfo(*v.Upc)
if v.Unit != "" {
skuName.Unit = v.Unit
} else {
if productInfo.Unit == "" {
if getNetUpcInfo.Unit != "" {
skuName.Unit = getNetUpcInfo.Unit
} else {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未查询到商品单位,请补充商品单位!")}
return retVal, err
}
} else {
skuName.Unit = productInfo.Unit
}
}
if v.SpecQuality != 0 {
skuName.Skus[0].SpecQuality = v.SpecQuality
skuName.Skus[0].Weight = utils.Float32ToInt(v.SpecQuality)
skuName.Skus[0].SpecUnit = model.SpecUnitNames[0]
} else {
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(v.Name)
if specQuality != 0 {
skuName.Skus[0].SpecQuality = specQuality
if specUnit == model.SpecUnitNames[1] || specUnit == model.SpecUnitNames[2] {
skuName.Skus[0].Weight = int(utils.Str2Int64(utils.Float64ToStr(float64(specQuality) * 1000)))
} else {
skuName.Skus[0].Weight = utils.Float32ToInt(specQuality)
}
} else {
if productInfo.SpecQuality == 0 {
if getNetUpcInfo.SpecQuality != 0 {
if getNetUpcInfo.SpecUnit == model.SpecUnitNames[1] || getNetUpcInfo.SpecUnit == model.SpecUnitNames[2] ||
getNetUpcInfo.SpecUnit == "KG" || getNetUpcInfo.SpecUnit == "l" {
skuName.Skus[0].Weight = int(utils.Str2Int64(utils.Float64ToStr(float64(getNetUpcInfo.SpecQuality) * 1000)))
} else {
skuName.Skus[0].Weight = utils.Float32ToInt(getNetUpcInfo.SpecQuality)
}
skuName.Skus[0].SpecQuality = getNetUpcInfo.SpecQuality
} else {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未查询到商品重量,请补充商品重量!")}
return retVal, err
}
} else {
if productInfo.Weight != 0 {
skuName.Skus[0].Weight = int(utils.Str2Int64(utils.Float64ToStr(float64(productInfo.Weight))))
} else {
skuName.Skus[0].Weight = utils.Float32ToInt(v.SpecQuality)
}
skuName.Skus[0].SpecQuality = productInfo.SpecQuality
}
}
if productInfo.SpecUnit == "" {
if getNetUpcInfo.SpecUnit != "" {
skuName.Skus[0].SpecUnit = getNetUpcInfo.SpecUnit
} else {
skuName.Skus[0].SpecUnit = model.SpecUnitNames[0]
}
} else {
skuName.Skus[0].SpecUnit = productInfo.SpecUnit
}
}
if len(productInfo.ImgList) > 0 {
skuName.Img = productInfo.ImgList[0]
} else {
skuName.Img = model.NOSkuNameImg
}
}
}
if skuName.Img == "" {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未查询到商品图片,请联系开发!")}
return retVal, err
}
suffix := skuName.Img[strings.LastIndex(skuName.Img, "."):]
if suffix != ".jpg" && suffix != ".png" && suffix != ".jpeg" && suffix != ".gif" {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, fmt.Sprintf("暂不支持的图片格式:[%v]", skuName.Img))}
return retVal, err
}
//需要把图片传到七牛云上
if !strings.Contains(skuName.Img, "image.jxc4.com") {
downloadURL, err := uploadImgStandard(skuName.Img)
if err != nil {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
return retVal, err
}
skuName.Img = downloadURL
// if resBinary, _, err := jxutils.DownloadFileByURL(skuName.Img); err == nil {
// if downloadURL, err := jxutils.UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix())+"origin"+skuName.Img[strings.LastIndex(skuName.Img, "/")+1:len(skuName.Img)]); err == nil {
// if img, _, err := datares.Binary2Image(resBinary, http.DetectContentType(resBinary)); err == nil {
// if img.Bounds().Dx() != datares.MainImgWidth || img.Bounds().Dy() != datares.MainImgHeight {
// if resBinary2, _, err := jxutils.DownloadFileByURL(downloadURL + model.SkuNameImgStandard); err == nil {
// if downloadURL2, err := jxutils.UploadExportContent(resBinary2, utils.Int64ToStr(time.Now().Unix())+skuName.Img[strings.LastIndex(skuName.Img, "/")+1:len(skuName.Img)]); err == nil {
// skuName.Img = downloadURL2
// } else {
// retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
// return retVal, err
// }
// } else {
// retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
// return retVal, err
// }
// } else {
// skuName.Img = downloadURL
// }
// } else {
// retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
// return retVal, err
// }
// } else {
// retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
// return retVal, err
// }
// } else {
// retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
// return retVal, err
// }
}
skuName.Status = model.SkuStatusNormal
skuName.IsGlobal = model.YES
if categoryID == 0 {
skuName.CategoryID = model.NoCatCatgoryID
} else {
skuName.CategoryID = categoryID
}
skuName.Skus[0].Status = model.SkuStatusNormal
_, err = AddSkuName(ctx, skuName, ctx.GetUserName())
if err != nil {
retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
return retVal, err
}
return retVal, err
}
taskParallel := tasksch.NewParallelTask("创建标品中", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, taskFunc, skuParams)
tasksch.HandleTask(taskParallel, task, true).Run()
createUpcSkuByExcelErrListInterface, err = taskParallel.GetResult(0)
case 2:
if len(createUpcSkuByExcelErrListInterface) > 0 {
for _, v := range createUpcSkuByExcelErrListInterface {
createUpcSkuByExcelErrList = append(createUpcSkuByExcelErrList, v.(*CreateUpcSkuByExcelErr))
}
if len(createUpcSkuByExcelErrList) > 0 {
err = writeToExcel(excelTitle, createUpcSkuByExcelErrList, ctx)
}
}
}
return result2, err
}
taskSeq := tasksch.NewSeqTask2("根据excel创建标品-序列任务", ctx, true, taskSeqFunc, 3)
tasksch.HandleTask(taskSeq, nil, true).Run()
hint = taskSeq.GetID()
return hint, err
}
func writeToExcel(excelTitle []string, dataList interface{}, ctx *jxcontext.Context) (err error) {
var sheetList []*excel.Obj2ExcelSheetConfig
var downloadURL, fileName string
excelConf := &excel.Obj2ExcelSheetConfig{
Title: "sheet1",
Data: dataList,
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
func RefreshJdDepot(ctx *jxcontext.Context) (err error) {
var (
pageSize = 20
searchResults []*jdapi.SearchDeleteWareResult
db = dao.GetDB()
// pageList []int
// skuIDs []int
)
for page := 1; page < 2; page++ {
searchDeleteWareResults, err := api.JdAPI.SearchDeleteWare("2020-04-22", "2020-04-22", page, pageSize)
if err == nil && len(searchDeleteWareResults) > 0 {
searchResults = append(searchResults, searchDeleteWareResults...)
}
}
for _, v := range searchResults {
param := &jdapi.OpSkuParam{
TraceID: ctx.GetTrackInfo(),
OutSkuID: utils.Int2Str(v.SkuID),
FixedStatus: jdapi.SkuFixedStatusDeleted,
}
time.Sleep(time.Second * 1)
_, err = api.JdAPI.UpdateSku2(param)
if err != nil {
globals.SugarLogger.Debugf("RefreshJdDepot UpdateSku2", err.Error())
continue
}
api.JdAPI.RefreshJdDepot(v.JdID)
sql := `
UPDATE thing_map SET vendor_thing_id = ?, sync_status = ?, updated_at = NOW()
WHERE thing_type = ? AND vendor_id = ? AND vendor_org_code = ? AND deleted_at = ? AND thing_id = ?
`
sqlParams := []interface{}{v.JdID, model.SyncFlagModifiedMask, model.ThingTypeSku, model.VendorIDJD, "320406", utils.DefaultTimeValue, v.SkuID}
dao.ExecuteSQL(db, sql, sqlParams)
_, err = SyncSkus(ctx, nil, []int{0}, []string{"320406"}, nil, []int{v.SkuID}, false)
time.Sleep(time.Second * 1)
// skuIDs = append(skuIDs, v.SkuID)
}
return err
}
//标准化上传图片。
//图片是非京西图片上传到七牛云转换为京西图片
func uploadImgStandard(imgUrl string) (downloadResult string, err error) {
if resBinary, _, err := jxutils.DownloadFileByURL(imgUrl); err == nil {
if downloadURL, err := jxutils.UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix())+"origin"+imgUrl[strings.LastIndex(imgUrl, "/")+1:len(imgUrl)]); err == nil {
if img, _, err := datares.Binary2Image(resBinary, http.DetectContentType(resBinary)); err == nil {
if img.Bounds().Dx() != datares.MainImgWidth || img.Bounds().Dy() != datares.MainImgHeight { //如果不是标准的800x800就再把图片格式化上传
if resBinary2, _, err := jxutils.DownloadFileByURL(downloadURL + model.SkuNameImgStandard); err == nil {
if downloadURL2, err := jxutils.UploadExportContent(resBinary2, utils.Int64ToStr(time.Now().Unix())+imgUrl[strings.LastIndex(imgUrl, "/")+1:len(imgUrl)]); err == nil {
downloadResult = downloadURL2
} else {
return downloadResult, err
}
} else {
return downloadResult, err
}
} else {
downloadResult = downloadURL
}
} else {
return downloadResult, err
}
} else {
return downloadResult, err
}
} else {
return downloadResult, err
}
return downloadResult, err
}
func AddSkuNameByUpc(ctx *jxcontext.Context, upc string, store *dao.StoreDetail, v *partner.SkuNameInfo) (err error) {
var (
db = dao.GetDB()
)
skuNames, err := dao.GetSkuNames(db, nil, []string{upc}, "", false)
if err != nil {
return err
}
//表示我们商品库中没有这个upc商品,如果有就直接关注上
if len(skuNames) == 0 {
skuNameExt := &model.SkuNameExt{
SkuName: model.SkuName{
Upc: &upc,
Status: model.SkuStatusNormal,
CategoryID: model.NoCatCatgoryID,
IsGlobal: model.YES,
Price: int(v.SkuList[0].VendorPrice),
},
Skus: []*model.SkuWithVendor{
&model.SkuWithVendor{
Sku: &model.Sku{
Status: model.SkuStatusNormal,
},
},
},
}
//我们商品库中有这个商品但是upc没有填则尝试用upc去查一下
productInfos, err2 := GetJdUpcCodeByName(ctx, "", upc)
getNetUpcInfo, err2 := api.AliUpcAPI.GetNetUpcInfo(upc)
err = err2
//表示用upc也没有找到这个商品
if len(productInfos) == 0 {
if getNetUpcInfo == nil || getNetUpcInfo.SpecQuality == 0 || getNetUpcInfo.Unit == "" {
return fmt.Errorf("此商品无规格无法创建upc :[%s] , unit: [%s], specQuality : [%v]", upc, getNetUpcInfo.Unit, getNetUpcInfo.SpecQuality)
}
if len(v.PictureList) > 0 {
skuNameExt.Img = v.PictureList[0]
} else {
img := getImgFromNet(db, upc)
if img != "" {
skuNameExt.Img = img
} else {
skuNameExt.Img = model.NOSkuNameImg
}
}
skuNameExt.Name = v.Name
skuNameExt.Unit = getNetUpcInfo.Unit
skuNameExt.Skus[0].SpecQuality = getNetUpcInfo.SpecQuality
skuNameExt.Skus[0].SpecUnit = getNetUpcInfo.SpecUnit
skuNameExt.Skus[0].Weight = utils.Float32ToInt(getNetUpcInfo.SpecQuality)
} else {
productInfo := productInfos[0]
if (productInfo.SpecQuality == 0 || productInfo.Unit == "") && (getNetUpcInfo == nil || getNetUpcInfo.SpecQuality == 0 || getNetUpcInfo.Unit == "") {
return fmt.Errorf("此商品无规格无法创建upc :[%s] , unit: [%s], specQuality : [%v]", upc, getNetUpcInfo.Unit, getNetUpcInfo.SpecQuality)
}
if productInfo.SpecQuality == 0 {
skuNameExt.Skus[0].SpecQuality = getNetUpcInfo.SpecQuality
skuNameExt.Skus[0].Weight = utils.Float32ToInt(getNetUpcInfo.SpecQuality)
} else {
skuNameExt.Skus[0].SpecQuality = productInfo.SpecQuality
skuNameExt.Skus[0].Weight = utils.Float32ToInt(productInfo.SpecQuality)
}
if productInfo.SpecUnit == "" {
skuNameExt.Skus[0].SpecUnit = getNetUpcInfo.SpecUnit
} else {
skuNameExt.Skus[0].SpecUnit = productInfo.SpecUnit
}
if len(productInfo.ImgList) > 0 {
skuNameExt.Img = productInfo.ImgList[0]
} else {
img := getImgFromNet(db, upc)
if img != "" {
skuNameExt.Img = img
} else {
skuNameExt.Img = model.NOSkuNameImg
}
}
}
if flag := checkAndUpdateUpc(ctx, db, skuNameExt, v, store); !flag {
if !strings.Contains(skuNameExt.Img, "image.jxc4.com") {
downloadURL, err := uploadImgStandard(skuNameExt.Img)
if err != nil {
skuNameExt.Img = model.NOSkuNameImg
} else {
skuNameExt.Img = downloadURL
}
}
if resBinary, _, err := jxutils.DownloadFileByURL(skuNameExt.Img); err == nil {
if model.ValidMimeTypes[http.DetectContentType(resBinary)] == 0 {
skuNameExt.Img = model.NOSkuNameImg
}
}
if skuNameExt.SpecUnit == model.SpecUnitNames[1] || skuNameExt.SpecUnit == model.SpecUnitNames[2] ||
skuNameExt.SpecUnit == "KG" || skuNameExt.SpecUnit == "l" {
skuNameExt.Skus[0].Weight = skuNameExt.Skus[0].Weight * 1000
}
outSkuNameExt, err := AddSkuName(ctx, skuNameExt, ctx.GetUserName())
if err != nil {
return err
}
buildStoreSkuBindInfosAndFocus(ctx, db, store, v, outSkuNameExt.ID)
}
} else {
buildStoreSkuBindInfosAndFocus(ctx, db, store, v, skuNames[0].ID)
}
return err
}
//该商品名规格在库中能查询出则更新upc不插入
func checkAndUpdateUpc(ctx *jxcontext.Context, db *dao.DaoDB, skuNameExt *model.SkuNameExt, v *partner.SkuNameInfo, store *dao.StoreDetail) (flag bool) {
skuNames2, err := dao.GetSkuNames(db, nil, nil, skuNameExt.Name, false)
if err != nil {
return false
}
if len(skuNames2) == 0 {
return false
}
//表示查到了需要把upc更新上去没查到就要新建
if skuNameExt.SpecQuality == skuNames2[0].SpecQuality {
skuNames2[0].Upc = skuNameExt.Upc
dao.UpdateEntity(db, skuNames2[0], "Upc")
buildStoreSkuBindInfosAndFocus(ctx, db, store, v, skuNames2[0].ID)
return true
}
return false
}
func getImgFromNet(db *dao.DaoDB, upc string) (img string) {
var result *aliupcapi.GetAliUpcInfoResult
upcDepot, err := dao.GetUpcDepot(db, upc)
if upcDepot == nil {
result, err = api.AliUpcAPI.GetAliUpcInfo(upc)
if err == nil {
err = dao.InsertUpcDepot(db, result)
}
} else {
result = upcDepot
}
img = result.Img
return img
}