1045 lines
32 KiB
Go
1045 lines
32 KiB
Go
package cms
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||
"git.rosy.net.cn/baseapi/utils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||
"git.rosy.net.cn/jx-callback/business/model"
|
||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
"git.rosy.net.cn/jx-callback/globals/api"
|
||
)
|
||
|
||
type SkuNamesInfo struct {
|
||
TotalCount int `json:"totalCount"`
|
||
SkuNames []*model.SkuNameExt `json:"skuNames"`
|
||
}
|
||
|
||
var (
|
||
ErrInputCatsDoesntMatch = errors.New("输入的类别列表不合法,需要输入一个父ID下的所有子类别")
|
||
)
|
||
|
||
var (
|
||
ebaiUploadRTFShopID string // 饿百找一个店用于调用SkuUploadRTF
|
||
)
|
||
|
||
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) (cats []*model.SkuCategory, err error) {
|
||
params := []interface{}{
|
||
utils.DefaultTimeValue,
|
||
}
|
||
sql := "SELECT * FROM sku_category WHERE deleted_at = ?"
|
||
if parentID != -1 {
|
||
sql += " AND parent_id = ?"
|
||
params = append(params, parentID)
|
||
}
|
||
sql += " ORDER BY level, seq"
|
||
return cats, dao.GetRows(nil, &cats, sql, params)
|
||
}
|
||
|
||
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.Name = strings.Trim(cat.Name, " ")
|
||
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
|
||
}
|
||
if err = dao.CreateEntity(nil, cat); err == nil {
|
||
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
|
||
}
|
||
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
|
||
}
|
||
if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, cat, valid, userName, nil, model.FieldJdSyncStatus, syncStatus); err == nil {
|
||
SetStoreCategorySyncStatus2(db, nil, []int{categoryID}, model.SyncFlagModifiedMask)
|
||
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 {
|
||
var skuIDs []int
|
||
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)
|
||
}
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func SetStoreCategorySyncStatus2(db *dao.DaoDB, storeIDs []int, catIDs []int, syncStatus int) (num int64, err error) {
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
for _, vendorID := range partner.GetSingleStoreVendorIDs() {
|
||
num2, err2 := dao.SetStoreCategorySyncStatus(db, vendorID, storeIDs, catIDs, syncStatus)
|
||
if err = err2; err != nil {
|
||
return 0, err
|
||
}
|
||
num += num2
|
||
}
|
||
dao.Commit(db)
|
||
return num, nil
|
||
}
|
||
|
||
func ReorderCategories(ctx *jxcontext.Context, parentID int, categoryIDs []int, userName string) (err error) {
|
||
var cats []*model.SkuCategory
|
||
parentCat := &model.SkuCategory{}
|
||
parentCat.ID = parentID
|
||
db := dao.GetDB()
|
||
if parentID != 0 {
|
||
err = dao.GetEntity(db, parentCat)
|
||
} else {
|
||
parentCat = nil
|
||
}
|
||
if err == nil {
|
||
if err = dao.GetEntitiesByKV(db, &cats, utils.Params2Map(model.FieldParentID, parentID), false); err == nil {
|
||
catsLen := len(cats)
|
||
if catsLen != len(categoryIDs) {
|
||
return ErrInputCatsDoesntMatch
|
||
}
|
||
catsMap := make(map[int]*model.SkuCategory, catsLen)
|
||
for _, cat := range cats {
|
||
catsMap[cat.ID] = cat
|
||
}
|
||
for k, v := range categoryIDs {
|
||
catsMap[v].Seq = k
|
||
catsMap[v].JdSyncStatus |= model.SyncFlagModifiedMask
|
||
if _, err = dao.UpdateEntity(db, catsMap[v], "Seq"); err != nil {
|
||
break
|
||
}
|
||
}
|
||
if err == nil {
|
||
_, err = CurVendorSync.SyncReorderCategories(ctx, db, parentID, false, userName)
|
||
}
|
||
}
|
||
}
|
||
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() {
|
||
dao.Rollback(db)
|
||
}()
|
||
if _, err = DeleteCategoryMap(ctx, db, categoryID); err == nil {
|
||
if num, err = dao.DeleteEntityLogically(db, cat, utils.Params2Map(model.FieldJdSyncStatus, model.SyncFlagDeletedMask), userName, nil); err == nil && num == 1 {
|
||
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,
|
||
model.FieldWscSyncStatus: model.SyncFlagDeletedMask,
|
||
}, ctx.GetUserName(), map[string]interface{}{
|
||
model.FieldCategoryID: categoryID,
|
||
model.FieldDeletedAt: utils.DefaultTimeValue,
|
||
})
|
||
}
|
||
|
||
func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku 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
|
||
WHERE t1.deleted_at = ?`
|
||
sqlParams := []interface{}{
|
||
utils.DefaultTimeValue,
|
||
utils.DefaultTimeValue,
|
||
}
|
||
if keyword != "" {
|
||
keywordLike := "%" + keyword + "%"
|
||
sql += " AND (t1.name LIKE ? OR t1.prefix LIKE ? OR t2.comment LIKE ? OR t1.upc LIKE ?"
|
||
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike)
|
||
|
||
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
|
||
sql += " OR t1.id = ? OR t2.id = ? OR t2.jd_id = ? OR t1.category_id = ?"
|
||
sqlParams = append(sqlParams, keywordInt64, 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 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["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 t2.jd_id IN (" + dao.GenQuestionMarks(len(vendorSkuIDs)) + ")"
|
||
sqlParams = append(sqlParams, 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.elm_img_hash_code,
|
||
t1.status,
|
||
t1.is_spu,
|
||
t1.img_hash_code,
|
||
t1.desc_img,
|
||
t1.upc`
|
||
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.elm_img_hash_code,
|
||
t1.status,
|
||
t1.is_spu,
|
||
t1.img_hash_code,
|
||
t1.desc_img,
|
||
t1.upc,
|
||
t1.jd_id,
|
||
t1.jd_sync_status,
|
||
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,
|
||
'","weight":', t2.weight, ',"jdID":', t2.jd_id, ',"categoryID":', t2.category_id, ',"nameID":', t2.name_id,
|
||
',"jdID":', t2.jd_id, ',"jdSyncStatus":', t2.jd_sync_status,
|
||
"}")), "]") skus_str,
|
||
CONCAT("[", GROUP_CONCAT(DISTINCT t3.place_code), "]") places_str
|
||
` + sql + `
|
||
ORDER BY t1.id DESC
|
||
LIMIT ? OFFSET ?`
|
||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||
if offset < 0 {
|
||
offset = 0
|
||
}
|
||
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)
|
||
for _, skuName := range skuNamesInfo.SkuNames {
|
||
if skuName.SkusStr != "" {
|
||
if err = utils.UnmarshalUseNumber([]byte(skuName.SkusStr), &skuName.Skus); err != nil {
|
||
dao.Rollback(db)
|
||
return nil, err
|
||
}
|
||
}
|
||
if skuName.PlacesStr != "" {
|
||
if err = utils.UnmarshalUseNumber([]byte(skuName.PlacesStr), &skuName.Places); err != nil {
|
||
dao.Rollback(db)
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
} 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")
|
||
}
|
||
}
|
||
|
||
if hasSensitiveWord, err := CheckHasSensitiveWord(skuNameExt.Name); hasSensitiveWord {
|
||
return nil, err
|
||
}
|
||
|
||
db := dao.GetDB()
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
dao.Rollback(db)
|
||
panic(r)
|
||
}
|
||
}()
|
||
if skuNameExt.Upc != "" {
|
||
err = dao.GetEntity(db, &skuNameExt.SkuName, "Upc")
|
||
if err == nil {
|
||
return nil, fmt.Errorf("UPC:%s重复", skuNameExt.Upc)
|
||
} else if !dao.IsNoRowsError(err) {
|
||
return nil, err
|
||
}
|
||
err = nil
|
||
}
|
||
skuNameExt.SkuName.Status = model.SkuStatusNormal
|
||
if skuNameExt.IsSpu == 1 {
|
||
skuNameExt.SkuName.JdSyncStatus = model.SyncFlagNewMask
|
||
}
|
||
dao.WrapAddIDCULDEntity(&skuNameExt.SkuName, userName)
|
||
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 globals.EnableStoreWrite {
|
||
imgContent, imgMD5, err := jxutils.DownloadFileByURL(skuNameExt.Img)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return nil, err
|
||
}
|
||
if skuNameExt.ImgHashCode == "" {
|
||
skuNameExt.ImgHashCode = imgMD5
|
||
} else if skuNameExt.ImgHashCode != imgMD5 {
|
||
dao.Rollback(db)
|
||
return nil, errors.New("图片HASH值不同")
|
||
}
|
||
imgHintMap, err := UploadImg2Platforms(ctx, nil, skuNameExt.Img, imgContent, "")
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return nil, err
|
||
}
|
||
skuNameExt.ImgWeimob = imgHintMap[model.VendorIDWSC]
|
||
skuNameExt.ImgEbai = imgHintMap[model.VendorIDEBAI]
|
||
|
||
if skuNameExt.DescImg != "" && getAndSetEbaiUploadRTFShopID() != "" {
|
||
skuNameExt.DescImgEbai, err = api.EbaiAPI.SkuUploadRTF(getAndSetEbaiUploadRTFShopID(), ebaiapi.BuildRFTFromImgs(skuNameExt.DescImg))
|
||
}
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return nil, err
|
||
}
|
||
}
|
||
if err = dao.CreateEntity(db, &skuNameExt.SkuName); err != nil {
|
||
dao.Rollback(db)
|
||
return nil, err
|
||
}
|
||
for _, sku := range skuNameExt.Skus {
|
||
dao.WrapAddIDCULDEntity(sku, userName)
|
||
sku.NameID = skuNameExt.ID
|
||
sku.JdSyncStatus = model.SyncFlagNewMask
|
||
sku.JdID = 0 //beginJDID
|
||
if err = dao.CreateEntity(db, sku); 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, 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{}, userName string) (num int64, err error) {
|
||
skuName := &model.SkuName{}
|
||
skuName.ID = nameID
|
||
db := dao.GetDB()
|
||
if err = dao.GetEntity(db, skuName); err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
newSkuName := utils.Interface2String(payload["name"])
|
||
if hasSensitiveWord, err := CheckHasSensitiveWord(newSkuName); hasSensitiveWord {
|
||
return 0, err
|
||
}
|
||
|
||
delete(payload, "isSpu")
|
||
delete(payload, "ImgHashCode")
|
||
delete(payload, "ImgWeimob")
|
||
delete(payload, "ImgEbai")
|
||
delete(payload, "descImgEbai")
|
||
|
||
valid := dao.StrictMakeMapByStructObject(payload, skuName, userName)
|
||
valid = utils.RemoveGeneralMapKeys(valid, model.FieldSpecQuality, model.FieldSpecUnit)
|
||
_, hasPlaces := payload["places"]
|
||
if len(valid) > 0 || hasPlaces {
|
||
globals.SugarLogger.Debugf("UpdateSkuName valid:%s", utils.Format4Output(valid, false))
|
||
dao.Begin(db)
|
||
defer dao.Rollback(db)
|
||
if upc, _ := valid["upc"].(string); upc != "" {
|
||
skuName := &model.SkuName{
|
||
Upc: upc,
|
||
}
|
||
err = dao.GetEntity(db, skuName, "Upc")
|
||
if err == nil {
|
||
return 0, fmt.Errorf("UPC:%s重复", upc)
|
||
} else if !dao.IsNoRowsError(err) {
|
||
return 0, err
|
||
}
|
||
err = nil
|
||
}
|
||
if globals.EnableStoreWrite {
|
||
if valid["img"] != nil {
|
||
imgContent, imgMD5, err2 := jxutils.DownloadFileByURL(valid["img"].(string))
|
||
if err = err2; err != nil {
|
||
return 0, err
|
||
}
|
||
valid["ImgHashCode"] = imgMD5
|
||
imgHintMap, err := UploadImg2Platforms(ctx, nil, valid["img"].(string), imgContent, "")
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return 0, err
|
||
}
|
||
valid["ImgWeimob"] = imgHintMap[model.VendorIDWSC]
|
||
valid["ImgEbai"] = imgHintMap[model.VendorIDEBAI]
|
||
}
|
||
if valid["descImg"] != nil {
|
||
descImg := valid["descImg"].(string)
|
||
if descImg != "" {
|
||
if getAndSetEbaiUploadRTFShopID() != "" {
|
||
valid["descImgEbai"], err = api.EbaiAPI.SkuUploadRTF(getAndSetEbaiUploadRTFShopID(), ebaiapi.BuildRFTFromImgs(descImg))
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return 0, err
|
||
}
|
||
}
|
||
} else {
|
||
valid["descImgEbai"] = ""
|
||
}
|
||
}
|
||
}
|
||
if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, skuName, valid, userName, nil, model.FieldJdSyncStatus, model.SyncFlagModifiedMask); err == nil && num == 1 {
|
||
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 {
|
||
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 {
|
||
return 0, errors.New("地点代码非法")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if err == nil {
|
||
sku := &model.Sku{}
|
||
_, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, sku, nil, userName, map[string]interface{}{
|
||
model.FieldNameID: nameID,
|
||
}, model.FieldJdSyncStatus, model.SyncFlagModifiedMask)
|
||
if err == nil {
|
||
skuIDs, err2 := dao.GetSkuIDByNames(db, []int{nameID})
|
||
if err = err2; err == nil && len(skuIDs) > 0 {
|
||
_, err = SetStoreSkuSyncStatus2(db, nil, partner.GetSingleStoreVendorIDs(), skuIDs, model.SyncFlagModifiedMask)
|
||
}
|
||
if err == nil {
|
||
dao.Commit(db)
|
||
_, err = CurVendorSync.SyncSku(ctx, db, nameID, -1, false, false, userName)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func SetStoreSkuSyncStatus2(db *dao.DaoDB, storeIDs []int, vendorIDs, skuIDs []int, syncStatus int) (num int64, err error) {
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
for _, vendorID := range vendorIDs {
|
||
num2, err2 := dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, skuIDs, syncStatus)
|
||
if err = err2; err != nil {
|
||
return 0, err
|
||
}
|
||
num += num2
|
||
}
|
||
dao.Commit(db)
|
||
return num, nil
|
||
}
|
||
|
||
func DeleteSkuName(ctx *jxcontext.Context, nameID int, userName string) (num int64, err error) {
|
||
db := dao.GetDB()
|
||
dao.Begin(db)
|
||
defer func() {
|
||
dao.Rollback(db)
|
||
}()
|
||
if _, err := dao.DeleteSkuNamePlace(db, nameID, nil); err != nil {
|
||
return 0, err
|
||
}
|
||
if _, err = DeleteStoreSku(ctx, db, nameID, 0); err != nil {
|
||
return 0, err
|
||
}
|
||
numSku, err := dao.DeleteEntityLogically(db, &model.Sku{}, map[string]interface{}{
|
||
model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
|
||
model.FieldStatus: model.SkuStatusDeleted,
|
||
}, userName, map[string]interface{}{
|
||
model.FieldNameID: nameID,
|
||
})
|
||
if err != nil {
|
||
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 {
|
||
return 0, err
|
||
}
|
||
dao.Commit(db)
|
||
if numSku > 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.NameID = nameID
|
||
sku.JdID = 0
|
||
if err = dao.CreateEntity(db, sku); err == nil {
|
||
result, err2 := GetSkuNames(ctx, "", 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{}, userName string) (num int64, err error) {
|
||
sku := &model.Sku{}
|
||
sku.ID = skuID
|
||
db := dao.GetDB()
|
||
if err = dao.GetEntity(db, sku); err != nil {
|
||
return 0, err
|
||
}
|
||
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 := model.SyncFlagModifiedMask
|
||
if valid["specQuality"] != nil || valid["specUnit"] != nil {
|
||
maskValue |= model.SyncFlagSpecMask
|
||
}
|
||
if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, sku, valid, userName, nil, model.FieldJdSyncStatus, maskValue); err == nil {
|
||
if num == 1 {
|
||
if num, 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 {
|
||
if _, err = SetStoreSkuSyncStatus2(db, nil, partner.GetSingleStoreVendorIDs(), []int{skuID}, model.SyncFlagModifiedMask); err == nil {
|
||
if maskValue&model.SyncFlagSpecMask != 0 {
|
||
err = refreshStoreSkuPrice(ctx, db, skuID)
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
err = ErrEntityNotExist
|
||
}
|
||
}
|
||
if err == nil {
|
||
dao.Commit(db)
|
||
_, err = CurVendorSync.SyncSku(ctx, db, -1, sku.ID, false, false, userName)
|
||
} else {
|
||
dao.Rollback(db)
|
||
}
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func refreshStoreSkuPrice(ctx *jxcontext.Context, db *dao.DaoDB, skuID int) (err error) {
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
for vendorID := range partner.PurchasePlatformHandlers {
|
||
storeSkuList, err := dao.GetStoreSkus2(db, vendorID, 0, []int{skuID}, false)
|
||
if err == nil {
|
||
for _, v := range storeSkuList {
|
||
v.Price = int64(jxutils.CaculateSkuPrice(int(v.UnitPrice), v.SpecQuality, v.SpecUnit, v.Unit))
|
||
storeSku := &model.StoreSkuBind{}
|
||
storeSku.ID = v.BindID
|
||
if _, err = dao.UpdateEntityLogically(db, storeSku, map[string]interface{}{
|
||
"Price": v.Price,
|
||
dao.GetSyncStatusStructField(model.VendorNames[vendorID]): v.StoreSkuSyncStatus | model.SyncFlagPriceMask,
|
||
}, ctx.GetUserName(), nil); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
}
|
||
dao.Commit(db)
|
||
return err
|
||
}
|
||
|
||
func DeleteSku(ctx *jxcontext.Context, skuID int, userName string) (num int64, err error) {
|
||
db := dao.GetDB()
|
||
dao.Begin(db)
|
||
defer func() {
|
||
dao.Rollback(db)
|
||
}()
|
||
|
||
if _, err = DeleteStoreSku(ctx, db, 0, skuID); err == nil {
|
||
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.Commit(db)
|
||
if num == 1 {
|
||
_, err = CurVendorSync.SyncSku(ctx, db, -1, sku.ID, false, false, userName)
|
||
} else {
|
||
err = ErrEntityNotExist
|
||
}
|
||
}
|
||
}
|
||
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.FieldWscSyncStatus: 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)
|
||
if err = dao.CreateEntity(db, placeBind); err == nil {
|
||
_, 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
|
||
if num, err = dao.DeleteEntity(db, placeBind, model.FieldNameID, model.FieldPlaceCode); err == nil {
|
||
if num == 1 {
|
||
_, err = CurVendorSync.SyncSku(ctx, db, nameID, -1, false, false, userName)
|
||
} else {
|
||
err = ErrEntityNotExist
|
||
}
|
||
}
|
||
return num, err
|
||
}
|
||
|
||
func GetVendorSku(ctx *jxcontext.Context, vendorID int, vendorSkuID string) (skuNameInfo *model.SkuNameExt, err error) {
|
||
if handler := CurVendorSync.GetMultiStoreHandler(vendorID); handler != nil {
|
||
return handler.ReadSku(vendorSkuID)
|
||
}
|
||
return nil, ErrCanNotFindVendor
|
||
}
|
||
|
||
func UploadImg2Platforms(ctx *jxcontext.Context, parentTask tasksch.ITask, imgURL string, imgData []byte, imgName string) (imgHintMap map[int]string, err error) {
|
||
task := tasksch.NewParallelTask("UploadImg2Platforms", nil, ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
vendorID := batchItemList[0].(int)
|
||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||
imgHint, err2 := handler.UploadImg(ctx, imgURL, imgData, imgName)
|
||
if err = err2; err == nil {
|
||
return [][]interface{}{
|
||
[]interface{}{
|
||
vendorID,
|
||
imgHint,
|
||
},
|
||
}, nil
|
||
}
|
||
}
|
||
return nil, err
|
||
}, []int{model.VendorIDEBAI, model.VendorIDWSC})
|
||
tasksch.HandleTask(task, parentTask, false).Run()
|
||
resultList, err := task.GetResult(0)
|
||
if err == nil {
|
||
imgHintMap = make(map[int]string)
|
||
for _, v := range resultList {
|
||
vList := v.([]interface{})
|
||
imgHintMap[vList[0].(int)] = vList[1].(string)
|
||
}
|
||
}
|
||
return imgHintMap, err
|
||
} |