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 }