package cms

import (
	"encoding/json"
	"errors"
	"fmt"
	"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
	"io"
	"math"
	"mime/multipart"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"

	"git.rosy.net.cn/jx-callback/globals/api/apimanager"

	beego "github.com/astaxie/beego/server/web"

	"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
// }

func GetVendorCategoriesWithMap(ctx *jxcontext.Context, vendorID int) (vendorCats []*dao.GetVendorCategoriesWithMapResult, err error) {
	if vendorID != model.VendorIDMTWM {
		return nil, fmt.Errorf("只支持美团！")
	}
	return dao.GetVendorCategoriesWithMap(dao.GetDB(), vendorID, 0)
}

// 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)
}

// 获取正确分类根据分类名称
func GetVendorCategoriesByName(vendorId int, name string) (vendorCats *model.SkuVendorCategory, err error) {
	sql := ` SELECT * FROM  sku_vendor_category WHERE vendor_id = ? AND  name LIKE  ? `
	err = dao.GetRow(dao.GetDB(), &vendorCats, sql, []interface{}{vendorId, "%" + name + "%"}...)
	return vendorCats, err
}

// 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)
		//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 > 3 {
		return nil, errors.New("Level必须为1或2,3")
	} 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分类")
		}
	} else if cat.Level == 3 {
		if cat.ParentID == 0 {
			return nil, errors.New("Level3的分类其父分类必须不为0")
		}
		parentCat := &model.SkuCategory{}
		parentCat.ID = cat.ParentID
		if err = dao.GetEntity(db, parentCat); err != nil {
			return nil, err
		}
		if parentCat.Level != 2 {
			return nil, errors.New("Level3的分类其父分类必须为Level2分类")
		}
	}
	if catsByName, err := dao.GetCategoriesByName(db, cat.Name, ""); err == nil && len(catsByName) > 0 {
		return nil, fmt.Errorf("已有分类名：[%v]，分类名不允许重复！", cat.Name)
	} else if err != nil {
		return nil, err
	}
	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
	}
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if err = dao.CreateEntity(db, cat); err != nil {
		dao.Rollback(db, txDB)
		return nil, err
	}
	if cat.IsExdSpec == model.NO {
		if err = OnCreateThing(ctx, db, nil, int64(cat.ID), model.ThingTypeCategory, model.SyncFlagNewMask, false); err != nil {
			dao.Rollback(db, txDB)
			return nil, err
		}
	}
	dao.Commit(db, txDB)
	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
				}
			}
		}

		txDB, _ := dao.Begin(db)
		defer func() {
			if r := recover(); r != nil {
				dao.Rollback(db, txDB)
				panic(r)
			}
		}()
		if num, err = dao.UpdateEntityLogically(db, cat, valid, userName, nil); err != nil {
			dao.Rollback(db, txDB)
			return 0, err
		}
		if cat.IsExdSpec == model.NO {
			if err = OnUpdateThing(ctx, db, nil, int64(categoryID), model.ThingTypeCategory); err != nil {
				dao.Rollback(db, txDB)
				return 0, err
			}
		}
		dao.Commit(db, txDB)

		SetStoreCategorySyncStatus2(db, nil, []int{categoryID}, model.SyncFlagModifiedMask)
		var skuIDs []int
		if valid["jdCategoryID"] != nil || valid["ebaiCategoryID"] != nil || valid["mtwmCategoryID"] != nil || valid["ddCategoryID"] != nil ||
			valid["jdPricePercentage"] != nil || valid["ebaiPricePercentage"] != nil || valid["mtwmPricePercentage"] != nil || valid["ddPricePercentage"] != 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 valid["ddPricePercentage"] != nil {
					vendorIDs = append(vendorIDs, model.VendorIDDD)
					syncStatus |= model.SyncFlagPriceMask
				} else if valid["ddCategoryID"] != nil {
					vendorIDs = append(vendorIDs, model.VendorIDDD)
				}
				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, onlySort int) (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
		}

		txDB, _ := dao.Begin(db)
		defer func() {
			if r := recover(); r != nil {
				dao.Rollback(db, txDB)
				panic(r)
			}
		}()
		for k, v := range categoryIDs {
			if catsMap[v] == nil {
				dao.Rollback(db, txDB)
				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, txDB)
				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, txDB)
					return err
				}
			}
		}
		dao.Commit(db, txDB)
		// 同步平台分类排序
		SetStoreCategorySyncStatus2(db, nil, categoryIDs, model.SyncFlagModifiedMask)
		// 只排序,不创建分类
		_, 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("还有商品类别使用此类别，不能删除")
		}
		txDB, _ := dao.Begin(db)
		defer func() {
			if r := recover(); r != nil {
				dao.Rollback(db, txDB)
				panic(r)
			}
		}()
		if _, err = DeleteCategoryMap(ctx, db, categoryID); err != nil {
			dao.Rollback(db, txDB)
			return 0, err
		}
		if err = OnDeleteThing(ctx, db, nil, int64(categoryID), model.ThingTypeCategory); err != nil {
			dao.Rollback(db, txDB)
			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, txDB)
			return 0, err
		}
		dao.Commit(db, txDB)
		_, 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.FieldTaoSyncStatus:  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 t1.img 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,
			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["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["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["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)
	}
	sqlData := `
		SELECT
		SQL_CALC_FOUND_ROWS
		DISTINCT
		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.img3,
		t1.img4,
		t1.img5,
		t1.img_watermark,
		t1.img_mix,
		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,
		t1.jds_stock_switch,
		t1.preparation_time,
		t1.best_seller,
		t1.sell_point,
		t1.sell_point_times,
		t1.tiktok_attribute,
		t1.mt_attribute,
		t1.ebai_attribute,
		t1.qua_pictures,
		t1.qua_effective_date,
		t1.qua_approval_date,
		t1.special_pictures
		`
	if isBySku {
		sqlData += " ,t2.id sku_id"
	}
	if isQueryMidPrice {
		sqlData += ",t4.mid_unit_price"
	}
	sqlData += sql + `
	ORDER BY t1.id DESC 
	LIMIT ? OFFSET ?`
	pageSize = jxutils.FormalizePageSize(pageSize)
	offset = jxutils.FormalizePageOffset(offset)
	sqlParams = append(sqlParams, pageSize, offset)
	skuNamesInfo = &SkuNamesInfo{}
	txDB, _ := dao.Begin(db) // todo 这里用事务的原因是，SQL_CALC_FOUND_ROWS会出错
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if err = dao.GetRowsTx(txDB, &skuNamesInfo.SkuNames, sqlData, sqlParams...); err == nil {
		skuNamesInfo.TotalCount = dao.GetLastTotalRowCount2(db, txDB)
		dao.Commit(db, txDB)

		// 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, txDB)
			// 		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, txDB)
			// 		return nil, err
			// 	}
			// }
			skuVendorCats, _ := dao.GetSkuVendorCategoryMaps(db, []int{skuName.ID}, []int{model.VendorIDMTWM, model.VendorIDEBAI, model.VendorIDJDShop, model.VendorIDJD, model.VendorIDDD}, nil)
			if len(skuVendorCats) > 0 {
				for _, v := range skuVendorCats {
					if v.VendorID == model.VendorIDJD {
						skuName.JdCategoryID = v.VendorCategoryID
					}
					if v.VendorID == model.VendorIDEBAI {
						skuName.EbaiCategoryID = v.VendorCategoryID
					}
					if v.VendorID == model.VendorIDMTWM {
						skuName.MtwmCategoryID = v.VendorCategoryID
					}
					if v.VendorID == model.VendorIDJDShop {
						skuName.JdsCategoryID = v.VendorCategoryID
					}
					if v.VendorID == model.VendorIDDD {
						skuName.DdCategoryID = v.VendorCategoryID
					}
				}
			}
			var (
				skus      []*model.Sku
				sqlParams = []interface{}{utils.DefaultTimeValue}
				sql       string
			)
			if !isBySku {
				sql = `
					SELECT * FROM sku WHERE deleted_at = ? AND name_id = ?
				`
				sqlParams = append(sqlParams, skuName.ID)
			} else {
				sql = `
					SELECT * FROM sku WHERE deleted_at = ? AND id = ?
				`
				sqlParams = append(sqlParams, skuName.SkuID)
			}
			if err = dao.GetRows(db, &skus, sql, sqlParams); err == nil {
				var skusVendors []*model.SkuWithVendor
				for _, v := range skus {
					skusVendor := &model.SkuWithVendor{
						Sku: v,
					}
					skusVendors = append(skusVendors, skusVendor)
				}
				skuName.Skus = skusVendors
				// thingMapMap, err2 := dao.GetThingMapMap(db, model.ThingTypeSku, nil, nil)
				// if err = err2; err == nil {
				// 	for _, skuName := range skuNamesInfo.SkuNames {
				// 		for _, v := range skuName.Skus {
				// 			v.MapList = thingMapMap[int64(v.ID)]
				// 		}
				// 	}
				// }
			}
			var (
				places     []*model.SkuNamePlaceBind
				placeCodes []int
			)
			sql2 := `
				SELECT * FROM sku_name_place_bind WHERE name_id = ?
			`
			sqlParams2 := []interface{}{skuName.ID}
			if err = dao.GetRows(db, &places, sql2, sqlParams2); err == nil {
				for _, v := range places {
					placeCodes = append(placeCodes, v.PlaceCode)
				}
				skuName.Places = placeCodes
			}
		}
	} else {
		dao.Rollback(db, txDB)
	}
	return skuNamesInfo, err
}

func CheckHasSensitiveWord(word string) (bool, string) {
	if hasSensitiveWord, sensitiveWord := IsSensitiveWordInList(word); hasSensitiveWord {
		return true, sensitiveWord
	}

	return false, ""
}

func IsSensitiveWordInList(str string) (bool, string) {
	wordList, err := dao.GetSensitiveWordList(-1)
	if err == nil {
		for _, value := range wordList {
			keyWord := value.Word
			if value.VendorID != -2 {
				checkHas := strings.Contains(str, keyWord)
				if checkHas {
					return true, keyWord
				}
			} else {
				var index int
				for index > 0 {
					index = strings.Index(keyWord, ",")
					keyWord = keyWord[:index-1]
					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 skuNameExt.QuaPictures != "" && (skuNameExt.QuaEffectiveDate == 0 || skuNameExt.QuaApprovalDate == 0) {
		return nil, errors.New("当商品资质图存在时,商品资质有效期和批准日期不能为空")
	}

	skuNameExt.Name = utils.TrimBlankChar(skuNameExt.Name)
	if hasSensitiveWord, word := CheckHasSensitiveWord(skuNameExt.Name); hasSensitiveWord {
		skuNameExt.Name = strings.ReplaceAll(skuNameExt.Name, word, "")
	}
	upc := utils.Pointer2String(skuNameExt.Upc)
	if upc == "" {
		skuNameExt.Upc = nil
	} else if !jxutils.IsUpcValid(upc) {
		return nil, fmt.Errorf("upc:%s不合法，请仔细检查", upc)
	}
	//有upc码时，单位不能为份
	if len(upc) != 0 && skuNameExt.Unit == "份" {
		return nil, errors.New("商品有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!")
				}
			}
		}
	}

	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格式的图片！")
		}
	}

	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	dao.WrapAddIDCULDEntity(&skuNameExt.SkuName, userName)
	if err = dao.CreateEntity(db, &skuNameExt.SkuName); err != nil {
		dao.Rollback(db, txDB)
		return nil, err
	}
	if err = OnCreateThing(ctx, db, nil, int64(skuNameExt.SkuName.ID), model.ThingTypeSkuName, model.SyncFlagNewMask, false); err != nil {
		dao.Rollback(db, txDB)
		return nil, err
	}
	for _, v := range skuNameExt.Skus {
		sku := v.Sku
		dao.WrapAddIDCULDEntity(sku, userName)
		sku.NameID = skuNameExt.ID
		sku.LadderBoxPrice = 0
		sku.LadderBoxNum = 0
		if err = dao.CreateEntity(db, sku); err != nil {
			dao.Rollback(db, txDB)
			return nil, err
		}
		if sku.EclpID == "" {
			if err = OnCreateThing(ctx, db, nil, int64(sku.ID), model.ThingTypeSku, 0, false); err != nil {
				dao.Rollback(db, txDB)
				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, txDB)
			return nil, err
		}
	}
	dao.Commit(db, txDB)

	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)

	updateOrCreateSkuVendorCategoryMap(db, ctx, outSkuNameExt.SkuName.ID, nil, skuNameExt, false)
	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, word := CheckHasSensitiveWord(newSkuName); hasSensitiveWord {
			payload["name"] = strings.ReplaceAll(payload["name"].(string), word, "")
		} else {
			payload["name"] = newSkuName
		}
	}

	delete(payload, "isSpu")
	delete(payload, "seq")

	flag := updateOrCreateSkuVendorCategoryMap(db, ctx, nameID, payload, nil, false)
	valid := dao.StrictMakeMapByStructObject(payload, skuName, userName)
	valid = utils.RemoveGeneralMapKeys(valid, model.FieldSpecQuality, model.FieldSpecUnit)
	_, hasPlaces := payload["places"]
	if len(valid) > 0 || hasPlaces || flag {
		if valid["Upc"] != nil {
			//if upc, _ := valid["Upc"].(string); upc == "" {
			upc, _ := valid["Upc"].(string)
			if upc == "" {
				valid["Upc"] = nil
			} else if !jxutils.IsUpcValid(upc) {
				return 0, fmt.Errorf("upc:%s不合法，请仔细检查", upc)
			}
			//有upc码时，单位不能为份
			if upc != "" && valid["unit"] != nil && valid["unit"].(string) == "份" {
				return 0, errors.New("商品有Upc码时，规格不能为份")
			}
		}

		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)
		}
		//美团商品传视频
		//这里实时传一下
		if valid["video"] != nil {
			video := valid["video"].(string)
			//删除
			if video == "" {

			} else {

			}
		}
		txDB, _ := dao.Begin(db)
		defer func() {
			if r := recover(); r != nil {
				dao.Rollback(db, txDB)
				panic(r)
			}
		}()
		if num, err = dao.UpdateEntityLogically(db, skuName, valid, userName, nil); err != nil {
			dao.Rollback(db, txDB)
			return 0, err
		}
		if !isExd && eclpID == "" {
			if err = OnUpdateThing(ctx, db, nil, int64(nameID), model.ThingTypeSkuName); err != nil {
				dao.Rollback(db, txDB)
				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, txDB)
					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, txDB)
						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, txDB)
					return 0, err
				}
				if sku.ExdSkuID == "" && sku.EclpID == "" {
					if err = OnUpdateThing(ctx, db, nil, int64(v.ID), model.ThingTypeSku); err != nil {
						dao.Rollback(db, txDB)
						return 0, err
					}
				}
			}
		}
		skuIDs, err2 := dao.GetSkuIDByNames(db, []int{nameID})
		if err = err2; err != nil {
			dao.Rollback(db, txDB)
			return 0, err
		}
		if len(skuIDs) > 0 {
			// 判断是否改价
			//if payload["price"] != nil {
			//	nowPrice, _ := payload["price"].(json.Number).Int64()
			//	if skuName.Price != int(nowPrice) && nowPrice != 0 && payload["skus"] != nil {
			//		for _, v1 := range payload["skus"].([]interface{}) {
			//			v := v1.(map[string]interface{})
			//			skuInfo := &aa{}
			//			if err := utils.Map2StructByJson(v, skuInfo, false); err != nil {
			//				globals.SugarLogger.Debugf("errr  %v", err)
			//				continue
			//			}
			//			var skuPrice int64 = 0
			//			if payload["unit"] == "份" { // 商品规格等于份的时候,标准重量保持为500g
			//				skuPrice = int64(float64(skuInfo.SpecQuality) / float64(500) * float64(nowPrice))
			//			} else {
			//				skuPrice = nowPrice
			//			}
			//			SetUpdateSkuPriceIfChange(db, skuPrice, nowPrice, skuInfo.Id)
			//		}
			//	}
			//}

			// 更新skuIds对应在store_sku_bind中的价格体系,解决老版本改价之前关注的商品,在价格修改后,store_sku_bind中京西价未修改的问题
			if _, err = SetStoreSkuSyncStatus2(db, nil, partner.GetSingleStoreVendorIDs(), skuIDs, model.SyncFlagModifiedMask); err != nil {
				dao.Rollback(db, txDB)
				return 0, err
			}
		}
		dao.Commit(db, txDB)

		errList := errlist.New()
		errList.AddErr(err)
		//_, err = CurVendorSync.SyncSku(ctx, db, nameID, -1, false, false, userName)
		//errList.AddErr(err)

		jxutils.CallMsgHandlerAsync(func() {
			storeIds, _ := GetSyncSkuStoreId(db, skuIDs)
			if len(storeIds) > model.NO {
				CurVendorSync.SyncStoresSkus(jxcontext.AdminCtx, nil, 0, db, partner.GetSingleStoreVendorIDs(), storeIds, skuIDs, false, false, true)
			}
		}, "")

		// 修改之前的bug,运营在修改商品之后,可能是价格或者其他什么发生变化,去重新更新一下各个平台的商品
		// 但是会出现商品所属门店或者分组比较多,然后更新异常慢,采用异步处理一下,但是本方法会出现很多更新异常
		// 商品未创建,图片啊,价格啊什么的
		//storeIds, err := GetSyncSkuStoreId(db, skuIDs)
		//if err != nil {
		//	return 0, err
		//}
		//_, err2 = CurVendorSync.SyncStoresSkus(jxcontext.AdminCtx, nil, 0, db, partner.GetSingleStoreVendorIDs(), storeIds, skuIDs, false, false, true)
		//errList.AddErr(err2)
		//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 getCategoryByName(name string) string {
	handler, _ := partner.GetPurchasePlatformFromVendorID(model.VendorIDJD).(partner.IPurchasePlatformStoreSkuHandler)
	vendorOrgCode := ""
	if beego.BConfig.RunMode == model.ServerTypeFruits {
		vendorOrgCode = jdapi.JdVendorOrgCodeFruit
	} else if beego.BConfig.RunMode == model.ServerTypePet {
		vendorOrgCode = jdapi.JdVendorOrgCodePet
	} else {
		vendorOrgCode = jdapi.JdVendorOrgCodeVagetable
	}
	vendorCategoryId, _ := handler.GetSkuCategoryIdByName(vendorOrgCode, name)
	return vendorCategoryId
}

// 获取抖音商品分类[抖音]
func getCategoryByImg(img ...string) string {
	imgs := make([]string, 0, 0)
	for _, v := range img {
		if v == "" {
			continue
		}
		imgs = append(imgs, v)
	}
	handler, _ := partner.GetPurchasePlatformFromVendorID(model.VendorIDDD).(partner.IPurchasePlatformStoreSkuHandler)
	vendorOrgCode := ""
	if beego.BConfig.RunMode == model.ServerTypeFruits {
		vendorOrgCode = "57939570"
	} else if beego.BConfig.RunMode == model.ServerTypePet {
		vendorOrgCode = "57939570"
	} else {
		vendorOrgCode = "57939570"
	}
	vendorCategoryId, _ := handler.GetSkuCategoryIdByName(vendorOrgCode, strings.Join(imgs, "|"))
	return vendorCategoryId
}

// 根据平台返回的分类id,获取本地绑定的映射分类id
func getJDCategoryLoadingLocalCategoryReflex(jdCategoryId, jdsCategoryID, ebaiCategoryID, mtwmCategoryID, taoCategoryID string, jxCategoryId int) (string, string, string, string, int) {
	cats, err := dao.GetCategoriesByName(dao.GetDB(), "", jdCategoryId)
	if len(cats) == 0 || err != nil {
		return jdsCategoryID, ebaiCategoryID, mtwmCategoryID, taoCategoryID, 0
	} else {
		if jdsCategoryID == "" && cats[0].JdsCategoryID != 0 {
			jdsCategoryID = utils.Int64ToStr(cats[0].JdsCategoryID)
		}
		if ebaiCategoryID == "" && cats[0].EbaiCategoryID != 0 {
			ebaiCategoryID = utils.Int64ToStr(cats[0].EbaiCategoryID)
		}
		if mtwmCategoryID == "" && cats[0].MtwmCategoryID != 0 {
			mtwmCategoryID = utils.Int64ToStr(cats[0].MtwmCategoryID)
		}
		if taoCategoryID == "" && cats[0].TaoCategoryID != 0 {
			taoCategoryID = utils.Int64ToStr(cats[0].TaoCategoryID)
		}
		if jxCategoryId == 0 || jxCategoryId == 291 {
			jxCategoryId = cats[0].ID
		}
	}
	return jdsCategoryID, ebaiCategoryID, mtwmCategoryID, taoCategoryID, jxCategoryId
}

func updateOrCreateSkuVendorCategoryMap(db *dao.DaoDB, ctx *jxcontext.Context, nameID int, payload map[string]interface{}, skuNameExt *model.SkuNameExt, isDelete bool) (flag bool) {
	if isDelete {
		skuVendorCatMaps, _ := dao.GetSkuVendorCategoryMaps(db, []int{nameID}, nil, nil)
		for _, v := range skuVendorCatMaps {
			v.DeletedAt = time.Now()
			v.LastOperator = ctx.GetUserName()
			dao.UpdateEntity(db, v, "DeletedAt", "LastOperator")
		}
		flag = true
	} else {
		updateOrCreate := func(vendorID, nameID int, vendorCatID string) {
			skuVendorCatMaps, _ := dao.GetSkuVendorCategoryMaps(db, []int{nameID}, []int{vendorID}, nil)
			if len(skuVendorCatMaps) > 0 {
				skuVendorCatMaps[0].VendorCategoryID = vendorCatID
				dao.UpdateEntity(db, skuVendorCatMaps[0], "VendorCategoryID")
			} else {
				skuVendorCatMap := &model.SkuVendorCategoryMap{
					NameID:           nameID,
					VendorID:         vendorID,
					VendorCategoryID: vendorCatID,
				}
				dao.WrapAddIDCULDEntity(skuVendorCatMap, ctx.GetUserName())
				dao.CreateEntity(db, skuVendorCatMap)
			}
		}

		// 京东的推荐分类id,可能是创建商品时用户添加的,如果用户没添加则,在平台获取京东的分类id
		// 在本地平台分类id和系统分类id的绑定表当中获取当前京东id对应系统i对应的美团和饿了么id
		// 将此id的值回填给当前的值!
		jdCategoryId := ""
		jdsCategoryID := ""
		ebaiCategoryID := ""
		mtwmCategoryID := ""
		taoCategoryID := ""
		ddCategoryID := ""
		jxCategoryID := 0
		if skuNameExt != nil {
			if skuNameExt.JdCategoryID != "" {
				jdCategoryId = skuNameExt.JdCategoryID
			} else {
				jdCategoryId = getCategoryByName(skuNameExt.Name)
			}

			if jdCategoryId != "" && jdCategoryId != "0" {
				jdsCategoryID, ebaiCategoryID, mtwmCategoryID, taoCategoryID, jxCategoryID = getJDCategoryLoadingLocalCategoryReflex(jdCategoryId, skuNameExt.JdsCategoryID, skuNameExt.EbaiCategoryID, skuNameExt.MtwmCategoryID, skuNameExt.TaoCategoryID, skuNameExt.CategoryID)
			} else {
				jdsCategoryID = skuNameExt.JdsCategoryID
				ebaiCategoryID = skuNameExt.EbaiCategoryID
				mtwmCategoryID = skuNameExt.MtwmCategoryID
				jxCategoryID = skuNameExt.CategoryID
			}

			if skuNameExt.DdCategoryID != "" {
				ddCategoryID = skuNameExt.DdCategoryID
			} else {
				// 抖音是根据商品图片获取商品分类的!
				ddCategoryID = getCategoryByImg(skuNameExt.DescImg, skuNameExt.Img, skuNameExt.Img2, skuNameExt.Img3, skuNameExt.Img4, skuNameExt.Img5)
			}
		} else {
			if payload["jdCategoryID"] != nil {
				value, ok := payload["jdCategoryID"].(string)
				if ok && value != "" && value != "0" {
					jdCategoryId = payload["jdCategoryID"].(string)
				} else {
					jdCategoryId = getCategoryByName(payload["name"].(string))
				}
			}

			if payload["jdsCategoryID"] != nil {
				value, ok := payload["jdCategoryID"].(string)
				if ok && value != "" && value != "0" {
					jdsCategoryID = payload["jdsCategoryID"].(string)
				}
			}
			if payload["ebaiCategoryID"] != nil {
				value, ok := payload["ebaiCategoryID"].(string)
				if ok && value != "" && value != "0" {
					ebaiCategoryID = payload["ebaiCategoryID"].(string)
				}
			}
			if payload["mtwmCategoryID"] != nil {
				value, ok := payload["mtwmCategoryID"].(string)
				if ok && value != "" && value != "0" {
					mtwmCategoryID = payload["mtwmCategoryID"].(string)
				}
			}
			if payload["categoryID2"] != nil && !utils.IsNil(payload["categoryID2"]) {
				var jxCategoryIDNumber int64
				if value, ok := payload["categoryID2"].(string); ok && value != "" {
					jxCategoryIDNumber = utils.Str2Int64(value)
				}
				if value, ok := payload["categoryID2"].(int64); ok && value != 0 {
					jxCategoryIDNumber = value
				}
				if value, ok := payload["categoryID2"].(json.Number); ok && value != "" {
					jxCategoryIDNumber, _ = value.Int64()
				}
				jxCategoryID = int(jxCategoryIDNumber)
			} else if payload["categoryID"] != nil && !utils.IsNil(payload["categoryID"]) {
				var jxCategoryIDNumber int64
				if value, ok := payload["categoryID"].(string); ok && value != "" {
					jxCategoryIDNumber = utils.Str2Int64(value)
				}
				if value, ok := payload["categoryID"].(int64); ok && value != 0 {
					jxCategoryIDNumber = value
				}
				if value, ok := payload["categoryID"].(json.Number); ok && value != "" {
					jxCategoryIDNumber, _ = value.Int64()
				}
				jxCategoryID = int(jxCategoryIDNumber)
			} else {
				jxCategoryID = 0
			}

			if jdCategoryId != "" {
				jdsCategoryID, ebaiCategoryID, mtwmCategoryID, taoCategoryID, jxCategoryID = getJDCategoryLoadingLocalCategoryReflex(jdCategoryId, jdsCategoryID, ebaiCategoryID, mtwmCategoryID, taoCategoryID, jxCategoryID)
			}

			if payload["ddCategoryID"] != nil {
				if value, ok := payload["ddCategoryID"].(string); ok && value != "" {
					ddCategoryID = value
				}
			} else {
				imgs := make([]string, 0)
				if payload["descImg"] != nil {
					imgs = append(imgs, payload["descImg"].(string))
				}
				if payload["img"] != nil {
					imgs = append(imgs, payload["descImg"].(string))
				}
				if payload["img2"] != nil {
					imgs = append(imgs, payload["img2"].(string))
				}
				if payload["img3"] != nil {
					imgs = append(imgs, payload["img3"].(string))
				}
				if payload["img4"] != nil {
					imgs = append(imgs, payload["img4"].(string))
				}
				if payload["img5"] != nil {
					imgs = append(imgs, payload["img5"].(string))
				}
				ddCategoryID = getCategoryByImg(imgs...)
				//ddCategoryID = getCategoryByImg(payload["descImg"].(string), payload["img"].(string), payload["img2"].(string), payload["img3"].(string), payload["img4"].(string), payload["img5"].(string))
			}
		}

		if jdsCategoryID != "" && jdsCategoryID != "0" {
			updateOrCreate(model.VendorIDJDShop, nameID, jdsCategoryID)
			flag = true
		}
		if ebaiCategoryID != "" && ebaiCategoryID != "0" {
			updateOrCreate(model.VendorIDEBAI, nameID, ebaiCategoryID)
			flag = true
		}
		if mtwmCategoryID != "" && mtwmCategoryID != "0" {
			updateOrCreate(model.VendorIDMTWM, nameID, mtwmCategoryID)
			flag = true
		}
		if ddCategoryID != "" && ddCategoryID != "0" {
			updateOrCreate(model.VendorIDDD, nameID, ddCategoryID)
			flag = true
		}
		if jdCategoryId != "" && jdCategoryId != "0" {
			updateOrCreate(model.VendorIDJD, nameID, jdCategoryId)
			flag = true
			if payload == nil {
				payload = make(map[string]interface{}, 0)
			}
			payload["jdCategoryID"] = jdCategoryId
		}
		if jxCategoryID != 0 && jxCategoryID != 291 {
			dao.ExecuteSQL(dao.GetDB(), `UPDATE sku_name SET category_id = ? WHERE id = ?`, []interface{}{jxCategoryID, nameID}...)
			flag = true
		}

	}
	return flag
}

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 SetUpdateSkuPriceIfChange(db *dao.DaoDB, skuPrice, nowPrice int64, skuId int) error {
	sql := ` UPDATE store_sku_bind s SET s.price = ?,s.unit_price = ?  WHERE s.sku_id = ? AND s.deleted_at = ?`
	param := []interface{}{skuPrice, nowPrice, skuId, utils.DefaultTimeValue}
	_, err := dao.ExecuteSQL(db, sql, param...)
	return err
}

// GetSyncSkuStoreId 当每个商品存在修改时,需要重新同步商品的信息,立马同步,获取需要同步的门店信息
func GetSyncSkuStoreId(db *dao.DaoDB, skus []int) ([]int, error) {
	sql := ` SELECT  * FROM store_sku_bind b
				INNER JOIN store  s on s.id = b.store_id
				WHERE b.sku_id IN (` + dao.GenQuestionMarks(len(skus)) + `) AND b.status = ? AND s.status <> ? AND b.deleted_at = ? `
	param := []interface{}{skus, model.YES, model.StoreStatusDisabled, utils.DefaultTimeValue}

	skuBind := make([]*model.StoreSkuBind, 0, 0)
	if err := dao.GetRows(db, &skuBind, sql, param); err != nil {
		return nil, err
	}

	storeIds := make([]int, 0, 0)
	for _, v := range skuBind {
		storeIds = append(storeIds, v.StoreID)
	}

	return storeIds, nil
}

func UpdateSkuImg(ctx *jxcontext.Context, skuID int, payload map[string]interface{}) (string, error) {
	var (
		db = dao.GetDB()
	)
	globals.SugarLogger.Debugf("UpdateSkuImg pre test data: %s\n", payload)
	if skuID == 0 {
		return "skuID必传", nil
	} else if payload["img"] == "" {
		return "所有 img 字段必传", nil
	}
	if _, err := dao.ExecuteSQL(db, `
    UPDATE sku_name s 
    SET s.img = ?,s.img2 = ?,s.img3 = ?,s.img4 = ?,s.img5 = ?,s.desc_img = ? 
    WHERE s.id = ? `, payload["img"], payload["img2"], payload["img3"], payload["img4"], payload["img5"], payload["descImg"], skuID); err != nil {
		return "数据库操作失败", err
	}
	return "", nil
}

func DeleteSkuName(ctx *jxcontext.Context, nameID int, userName string) (num int64, err error) {
	db := dao.GetDB()
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()

	if _, err := dao.DeleteSkuNamePlace(db, nameID, nil); err != nil {
		dao.Rollback(db, txDB)
		return 0, err
	}
	if _, err = DeleteStoreSku(ctx, db, nameID, 0); err != nil {
		dao.Rollback(db, txDB)
		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, txDB)
				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, txDB)
				return 0, err
			}
		}
	}

	if err = OnDeleteThing(ctx, db, nil, int64(nameID), model.ThingTypeSkuName); err != nil {
		dao.Rollback(db, txDB)
		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, txDB)
		return 0, err
	}
	dao.Commit(db, txDB)

	if len(skuList) > 0 {
		_, err = CurVendorSync.SyncSku(ctx, db, skuName.ID, -1, false, false, userName)
	}
	updateOrCreateSkuVendorCategoryMap(db, ctx, nameID, nil, nil, true)
	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
	sku.LadderBoxPrice = 0
	sku.LadderBoxNum = 0
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if err = dao.CreateEntity(db, sku); err != nil {
		dao.Rollback(db, txDB)
		return nil, err
	}
	if err = OnCreateThing(ctx, db, nil, int64(sku.ID), model.ThingTypeSku, 0, false); err != nil {
		dao.Rollback(db, txDB)
		return nil, err
	}
	dao.Commit(db, txDB)

	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
		}
	}
	//增加规格则同步到门店，目前只做了京东商城的。
	storeSkus, err := dao.GetStoreSkusByNameIDs(db, []int{model.JdShopMainStoreID}, nameID)
	if len(storeSkus) > 0 {
		storeIDs := make(map[int]int)
		storeMaps, err2 := dao.GetStoresMapList(db, []int{model.VendorIDJDShop}, nil, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "")
		err = err2
		for _, v := range storeMaps {
			storeSkus2, err2 := dao.GetStoreSkusByNameIDs(db, []int{v.StoreID}, nameID)
			err = err2
			if len(storeSkus2) > 0 {
				storeIDs[v.StoreID] = v.StoreID
			}
		}
		skuBindInfos := []*StoreSkuBindInfo{}
		for _, v := range storeIDs {
			skus2 := []*StoreSkuBindSkuInfo{}
			skuBindInfo := &StoreSkuBindInfo{
				StoreID: v,
			}
			sku2 := &StoreSkuBindSkuInfo{
				SkuID: sku.ID,
			}
			skus2 = append(skus2, sku2)
			skuBindInfo.Skus = skus2
			skuBindInfos = append(skuBindInfos, skuBindInfo)
		}
		FocusStoreSkusBySku(ctx, skuBindInfos, true, true)
	}
	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 {
		txDB, _ := dao.Begin(db)
		defer func() {
			if r := recover(); r != nil {
				dao.Rollback(db, txDB)
				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, txDB)
			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, txDB)
			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, txDB)
				return 0, err
			}
		}
		dao.Commit(db, txDB)

		if _, err = SetStoreSkuSyncStatus2(db, nil, partner.GetSingleStoreVendorIDs(), []int{skuID}, model.SyncFlagModifiedMask); err == nil {
			if maskValue&model.SyncFlagSpecMask != 0 {
				err = refreshStoreSkuPrice(ctx, db, skuID)
			}
			if valid["status"] != nil {
				SetStoreSkuSyncStatus2(db, nil, partner.GetSingleStoreVendorIDs(), []int{skuID}, model.SyncFlagSaleMask)
			}
		}
		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.TaoSyncStatus = v.TaoSyncStatus | 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()
			txDB, _ := dao.Begin(db)
			defer func() {
				if r := recover(); r != nil || err != nil {
					dao.Rollback(db, txDB)
					if r != nil {
						panic(r)
					}
				}
			}()
			dao.UpdateEntity(db, storeSku, "Price", "JdSyncStatus", "MtwmSyncStatus", "TaoSyncStatus", "EbaiSyncStatus", "JxPrice", "LastOperator")
			dao.Commit(db, txDB)
			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()
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()

	if _, err = DeleteStoreSku(ctx, db, 0, skuID); err != nil {
		dao.Rollback(db, txDB)
		return 0, err
	}
	if err = OnDeleteThing(ctx, db, nil, int64(skuID), model.ThingTypeSku); err != nil {
		dao.Rollback(db, txDB)
		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, txDB)
		return 0, err
	}
	dao.Commit(db, txDB)
	if num == 1 {
		_, err = CurVendorSync.SyncSku(ctx, db, -1, sku.ID, false, false, userName)
	}
	err = deleteJdsSku(db, skuID)
	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.FieldTaoSyncStatus:  model.SyncFlagDeletedMask,
				model.FieldEbaiSyncStatus: model.SyncFlagDeletedMask,
				model.FieldJdsSyncStatus:  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)

	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if err = dao.CreateEntity(db, placeBind); err != nil {
		dao.Rollback(db, txDB)
		return nil, err
	}
	if err = OnUpdateThing(ctx, db, nil, int64(nameID), model.ThingTypeSkuName); err != nil {
		dao.Rollback(db, txDB)
		return nil, err
	}
	dao.Commit(db, txDB)

	_, 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

	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if num, err = dao.DeleteEntity(db, placeBind, model.FieldNameID, model.FieldPlaceCode); err != nil || num == 0 {
		dao.Rollback(db, txDB)
		if err == nil {
			err = ErrEntityNotExist
		}
		return 0, err
	}
	if err = OnUpdateThing(ctx, db, nil, int64(nameID), model.ThingTypeSkuName); err != nil {
		dao.Rollback(db, txDB)
		return 0, err
	}
	dao.Commit(db, txDB)

	_, 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("商品数据不匹配！")
			}
		}

		txDB, _ := dao.Begin(db)
		defer func() {
			if r := recover(); r != nil {
				dao.Rollback(db, txDB)
				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, txDB)
			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, txDB)
		}
	}
	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) {
	appOrgCode := ""
	if beego.BConfig.RunMode == model.ServerTypeFruits {
		appOrgCode = jdapi.JdVendorOrgCodeFruit
	} else if beego.BConfig.RunMode == model.ServerTypePet {
		appOrgCode = jdapi.JdVendorOrgCodePet
	} else {
		appOrgCode = jdapi.JdVendorOrgCodeVagetable
	}
	var (
		apijd       = apimanager.CurAPIManager.GetAPI(model.VendorIDJD, appOrgCode).(*jdapi.API)
		productInfo []*jdapi.ProductInfo
	)
	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 = apijd.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 {
		//productInfo, err = apijd.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
		//}
		productInfos, err = GetJdUpcCodeByCode(ctx, upcCode)
		if len(productInfos) == 0 {
			if configs, err := dao.QueryConfigs(dao.GetDB(), "mtwmCookieStr", model.ConfigTypeCookie, ""); err == nil {
				api.MtwmAPI.SetCookieWithStr(configs[0].Value)
			}
			if result, err := api.MtwmAPI.GetStandardProductListWithCond(upcCode); err == nil && result != nil {
				productInfon := &jdapi.ProductInfo{
					OriginalName: result.Name,
					OriginalSpec: result.Spec,
				}
				// _, name, _, specUnit, unit, specQuality := jxutils.SplitSkuName(productInfo.OriginalName)
				productInfon.Name = name
				productInfon.SpecUnit = result.SpecUnit
				productInfon.Unit = result.Unit
				productInfon.SpecQuality = float32(result.SpecNew)
				productInfon.ImgList = strings.Split(result.Pic, ",")
				productInfon.Weight = float32(result.Weight)
				productInfon.Price = result.AvgPrice
				productInfon.BrandName = result.BrandNamePath
				productInfos = append(productInfos, productInfon)
			}
		}
	}
	return productInfos, err
}

func UpdateSkuNamesExPrefix(ctx *jxcontext.Context, nameIDs []int, imgWaterMark string, vendorID 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,
							"imgWaterMark":  imgWaterMark,
							"exVendorID":    vendorID,
						}
						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
							payload["imgWaterMark"] = nil
							payload["exVendorID"] = 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, []int{vendorID}, nil, false, []int{skuList[0].ID}, nil, model.SyncFlagModifiedMask, true, true)
								} else {
									skuName := &model.SkuName{
										ExPrefix:      exPrefix,
										ExPrefixBegin: &fromTimeP,
										ExPrefixEnd:   &toTimeP,
										ImgWatermark:  imgWaterMark,
										ExVendorID:    vendorID,
									}
									skuName.ID = nameID
									skuName.LastOperator = ctx.GetLoginID()
									skuName.UpdatedAt = time.Now()
									txDB, _ := dao.Begin(db)
									defer func() {
										if r := recover(); r != nil {
											dao.Rollback(db, txDB)
											panic(r)
										}
									}()
									_, err = dao.UpdateEntity(db, skuName, "ImgWatermark", "ExVendorID", "ExPrefix", "ExPrefixBegin", "ExPrefixEnd", "LastOperator", "UpdatedAt")
									dao.Commit(db, txDB)
								}
							}
						}
						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, []int{vendorID}, 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 {
					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
	)
	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 {
							if upc != "" {
								unit = ""
							} else {
								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)
					sku     *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
					}
					//有upc码时，单位不能为份
					if v.Unit == "份" {
						return nil, errors.New("商品有Upc码时，规格不能为份")
					}
					skuName.Upc = v.Upc
				} else {
					retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "商品的条码不能为空！")}
					return retVal, err
				}
				isUpdate := false
				sql := `
					SELECT * FROM sku_name WHERE upc = ? AND deleted_at = ?
				`
				sqlParams := []interface{}{*v.Upc, utils.DefaultTimeValue}
				if err = dao.GetRow(db, &sku, sql, sqlParams); err == nil && sku != nil {
					//retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "商品在京西库中已存在！")}
					//return retVal, err
					isUpdate = true
				}
				productInfos, err := GetJdUpcCodeByCode(ctx, *v.Upc)
				if err != nil {
					retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
					return retVal, err
				}
				var productInfo = &jdapi.ProductInfo{}
				if len(productInfos) == 0 {
					if configs, err := dao.QueryConfigs(dao.GetDB(), "mtwmCookieStr", model.ConfigTypeCookie, ""); err == nil {
						api.MtwmAPI.SetCookieWithStr(configs[0].Value)
					}

					//result, err := api.MtwmAPI.GetStandardProductListWithCond(*skuName.Upc)
					//if result != nil {
					result, err := api.JdAPI.GetJdUpcCodeByName("", *skuName.Upc, 1, 5)
					if result != nil && len(result) != 0 {
						productInfo.OriginalName = result[0].OriginalName
						productInfo.OriginalSpec = result[0].OriginalSpec
						productInfo.Name = result[0].Name
						productInfo.SpecUnit = result[0].SpecUnit
						productInfo.Unit = result[0].Unit
						productInfo.SpecQuality = result[0].SpecQuality
						productInfo.ImgList = result[0].ImgList
						if result[0].Img != "" {
							productInfo.ImgList = append(productInfo.ImgList, productInfo.Img)
						}
						productInfo.Weight = result[0].Weight
						productInfo.BrandName = result[0].BrandName
						setImgs(skuName, productInfo.ImgList)
						//	productInfo.OriginalName = result.Name
						//	productInfo.OriginalSpec = result.Spec
						//	productInfo.Name = result.Name
						//	productInfo.SpecUnit = result.SpecUnit
						//	productInfo.Unit = result.Unit
						//	productInfo.SpecQuality = float32(result.SpecNew)
						//	productInfo.ImgList = strings.Split(result.Pic, ",")
						//	productInfo.Weight = float32(result.Weight)
						//	productInfo.BrandName = result.BrandNamePath
						//	setImgs(skuName, productInfo.ImgList)
					} else {
						retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "美团cookie过期或者没查询到")}
						return retVal, err
					}
				} else {
					productInfo = productInfos[0]
				}
				if productInfo.Name == "" {
					if v.Name != "" {
						productInfo.Name = v.Name
					} else if productInfo.OriginalName != "" {
						productInfo.Name = productInfo.OriginalName
					} else {
						retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "需要填上一个合适的商品名！")}
						return retVal, err
					}
					skuName.Name = productInfo.Name
				} else {
					skuName.Name = productInfo.Name
				}
				if v.Price == 0 {
					if productInfo.Price != 0 {
						skuName.Price = productInfo.Price
					} else {
						retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, "未查询到商品售价，请补充商品售价！")}
						return retVal, err
					}
				} else {
					skuName.Price = v.Price
				}
				// 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(math.Floor(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 {
					setImgs(skuName, productInfo.ImgList)
				} 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
				}
				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
				//需要把图片传到七牛云上, 很难受
				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 skuName.Img2 != "" {
					if !strings.Contains(skuName.Img2, "image.jxc4.com") {
						downloadURL, err := uploadImgStandard(skuName.Img2)
						if err != nil {
							retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
							return retVal, err
						}
						skuName.Img2 = downloadURL
					}
				}
				if skuName.Img3 != "" {
					if !strings.Contains(skuName.Img3, "image.jxc4.com") {
						downloadURL, err := uploadImgStandard(skuName.Img3)
						if err != nil {
							retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
							return retVal, err
						}
						skuName.Img3 = downloadURL
					}
				}
				if skuName.Img4 != "" {
					if !strings.Contains(skuName.Img4, "image.jxc4.com") {
						downloadURL, err := uploadImgStandard(skuName.Img4)
						if err != nil {
							retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
							return retVal, err
						}
						skuName.Img4 = downloadURL
					}
				}
				if skuName.Img5 != "" {
					if !strings.Contains(skuName.Img5, "image.jxc4.com") {
						downloadURL, err := uploadImgStandard(skuName.Img5)
						if err != nil {
							retVal = []*CreateUpcSkuByExcelErr{buildCreateUpcSkuByExcelErr(v, err.Error())}
							return retVal, err
						}
						skuName.Img5 = downloadURL
					}
				}

				// 标品不存在规格是默认为包
				if (skuName.Unit == "份" && *skuName.Upc != "") || skuName.Unit == "" {
					skuName.Unit = "包"
				}
				if !isUpdate {
					_, err = AddSkuName(ctx, skuName, ctx.GetUserName())
				} else {
					var data []*model.SkuVendorCategoryMap
					err = dao.GetRows(db, &data, `SELECT * FROM sku_vendor_category_map WHERE name_id = ? AND deleted_at = ?`, []interface{}{sku.ID, utils.DefaultTimeValue}...)

					sku.Name = skuName.Name
					sku.Img = skuName.Img
					sku.Img2 = skuName.Img2
					sku.Img3 = skuName.Img3
					sku.Img4 = skuName.Img4
					sku.Img5 = skuName.Img5
					sku.Unit = skuName.Unit
					dao.UpdateEntity(db, sku, "Name", "Img", "Img2", "Img3", "Img4", "Img5", "Unit")
					payload := make(map[string]interface{}, 0)
					payload["categoryID2"] = utils.Int2Str(sku.CategoryID)
					payload["categoryID"] = utils.Int2Str(sku.CategoryID)
					payload["descImg"] = sku.DescImg
					payload["img"] = sku.Img
					payload["img2"] = sku.Img2
					payload["img3"] = sku.Img3
					payload["img4"] = sku.Img4
					payload["img5"] = sku.Img5
					for _, d := range data {
						switch d.VendorID {
						case model.VendorIDJD:
							payload["jdCategoryID"] = d.VendorCategoryID
						case model.VendorIDMTWM:
							payload["mtwmCategoryID"] = d.VendorCategoryID
						case model.VendorIDJDShop:
						case model.VendorIDDD:
							payload["ddCategoryID"] = d.VendorCategoryID
						case model.VendorIDEBAI:
							payload["ebaiCategoryID"] = d.VendorCategoryID
						}
					}
					updateOrCreateSkuVendorCategoryMap(db, ctx, sku.ID, payload, nil, false)
				}
				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 {
			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()
		// skuBindInfos []*StoreSkuBindInfo
	)
	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
				}
			}
			if skuNameExt.Name == "" {
				skuNameExt.Name = v.SkuList[0].SkuName
			} else {
				skuNameExt.Name = v.Name
			}
			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 productInfo.Name == "" {
				if v.Name == "" {
					skuNameExt.Name = v.SkuList[0].SkuName
				} else {
					skuNameExt.Name = v.Name
				}
			} else {
				skuNameExt.Name = productInfo.Name
			}
			if productInfo.Unit == "" {
				skuNameExt.Unit = getNetUpcInfo.Unit
			} else {
				skuNameExt.Unit = productInfo.Unit
			}
		}
		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.Skus[0].SpecUnit == model.SpecUnitNames[1] || skuNameExt.Skus[0].SpecUnit == model.SpecUnitNames[2] ||
				skuNameExt.Skus[0].SpecUnit == "KG" || skuNameExt.Skus[0].SpecUnit == "l" {
				skuNameExt.Skus[0].Weight = skuNameExt.Skus[0].Weight * 1000
			}
			outSkuNameExt, err := AddSkuName(ctx, skuNameExt, ctx.GetUserName())
			if err != nil {
				return err
			}
			// skuBindInfo := &StoreSkuBindInfo{
			// 	NameID:    outSkuNameExt.SkuName.ID,
			// 	IsFocus:   1,
			// 	UnitPrice: outSkuNameExt.SkuName.Price,
			// }
			// skuBindInfos = append(skuBindInfos, skuBindInfo)
			// updateStoresSkusWithoutSync(ctx, db, []int{store.ID}, skuBindInfos, false)
			buildStoreSkuBindInfosAndFocus(ctx, db, store, v, outSkuNameExt.ID)
		}
	} else {
		// skuBindInfo := &StoreSkuBindInfo{
		// 	NameID:    skuNames[0].ID,
		// 	IsFocus:   1,
		// 	UnitPrice: skuNames[0].Price,
		// }
		// skuBindInfos = append(skuBindInfos, skuBindInfo)
		// updateStoresSkusWithoutSync(ctx, db, []int{store.ID}, skuBindInfos, false)
		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")
		// var skuBindInfos []*StoreSkuBindInfo
		// skuBindInfo := &StoreSkuBindInfo{
		// 	NameID:    skuNames2[0].ID,
		// 	IsFocus:   1,
		// 	UnitPrice: skuNames2[0].Price,
		// }
		// skuBindInfos = append(skuBindInfos, skuBindInfo)
		// updateStoresSkusWithoutSync(ctx, db, []int{store.ID}, skuBindInfos, false)
		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
}

func deleteJdsSku(db *dao.DaoDB, skuID int) (err error) {
	storeBinds, err := dao.GetStoresSkusInfo(db, []int{model.JdShopMainStoreID}, []int{skuID})
	if err == nil && len(storeBinds) > 0 {
		err = api.JdShopAPI.DeleteSku(storeBinds[0].JdsID)
	}
	return err
}

func UpdateSkuExinfoMap(ctx *jxcontext.Context, nameIDs []int, imgWaterMark string, brandID, vendorID int, vendorOrgCode, exPrefix, fromTime, toTime string, isAsync, isContinueWhenError bool, storeIds0 []int) (hint string, err error) {
	var (
		fromTimeP time.Time
		toTimeP   time.Time
		db        = dao.GetDB()
		// skuIDs    []int
	)
	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) {
			nameID := batchItemList[0].(int)
			skuEx := &model.SkuExinfoMap{
				NameID:       nameID,
				ImgWatermark: imgWaterMark,
				ExPrefix:     exPrefix,
				VendorID:     vendorID,
				BeginAt:      fromTimeP,
				EndAt:        toTimeP,
				BrandID:      brandID,
			}
			dao.WrapAddIDCULDEntity(skuEx, ctx.GetUserName())
			if imgWaterMark != "" {
				if skuNames, err := dao.GetSkuNames(db, []int{nameID}, nil, "", false); err == nil {
					if ImgMix := jxutils.MixWatermarkImg(imgWaterMark, skuNames[0].Img, &fromTimeP, &toTimeP); ImgMix != "" {
						skuEx.ImgWatermarkMix = ImgMix
					}
				}
			}
			skuExs, _ := dao.GetSkuExinfos(db, []int{nameID}, []int{vendorID}, "", utils.ZeroTimeValue, utils.ZeroTimeValue)
			if len(skuExs) > 0 {
				skuEx2 := skuExs[0]
				skuEx2.DeletedAt = time.Now()
				skuEx2.LastOperator = ctx.GetUserName()
				dao.UpdateEntity(db, skuEx2, "DeletedAt", "LastOperator")
				dao.CreateEntity(db, skuEx)
			} else {
				dao.CreateEntity(db, skuEx)
			}
			now := utils.Time2Date(time.Now())
			if now.Sub(fromTimeP) >= 0 && now.Sub(toTimeP) <= 0 {
				var skuIDs []int
				skuList, err2 := dao.GetSkus(db, nil, []int{nameID}, nil, nil, nil)
				if err = err2; err == nil {
					if len(skuList) > 0 {
						for _, v := range skuList {
							skuIDs = append(skuIDs, v.ID)
						}

						globals.SugarLogger.Debugf("---------1test := %s", utils.Format4Output(partner.IsMultiStore(vendorID), false))
						if partner.IsMultiStore(vendorID) {
							for _, v := range skuIDs {
								OnUpdateThing(ctx, db, nil, int64(v), model.ThingTypeSku)
							}
						} else {
							var storeIDs []int
							if len(storeIds0) != 0 {
								storeIDs = storeIds0
							} else if brandID != 0 {
								if stores, _ := dao.GetStoreList(db, nil, nil, nil, []int{brandID}, nil, ""); len(stores) > 0 {
									for _, v := range stores {
										storeIDs = append(storeIDs, v.ID)
									}
								}
							}
							globals.SugarLogger.Debugf("---------2test storeIDs:= %s", utils.Format4Output(storeIDs, false))
							SetStoreSkuSyncStatus2(db, storeIDs, []int{vendorID}, skuIDs, model.SyncFlagModifiedMask)
						}
					}
				}
			}
			return retVal, err
		}, nameIDs)
	tasksch.HandleTask(task, nil, true).Run()
	if isAsync {
		hint = task.GetID()
	} else {
		_, err = task.GetResult(0)
		hint = "1"
	}
	return hint, err
}

func UpdateVendorImg(ctx *jxcontext.Context, storeId int, imgWaterMark string, vendorID int, exPrefix string, fromTime, toTime string, isAsync, isContinueWhenError bool) (hint string, err error) {
	var (
		fromTimeP time.Time
		toTimeP   time.Time
		db        = dao.GetDB()
		// skuIDs    []int
		i       int = 0
		imgList     = make([]string, 0, 0)
	)
	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) {
			storeDetail, err := dao.GetStoreDetail(db, storeId, vendorID, "")
			if err != nil {
				return nil, err
			}

			switch vendorID {
			case model.VendorIDMTWM:
				var api *mtwmapi.API //= mtwm.GetAPI(fromStore.VendorOrgCode, fromStore.ID, fromStore.VendorStoreID)
				if storeDetail.VendorOrgCode == globals.Mtwm2Code {
					api = mtwmapi.New(beego.AppConfig.DefaultString("mtwmAppID2", ""), beego.AppConfig.DefaultString("mtwmSecret2", ""), beego.AppConfig.DefaultString("mtwmCallbackURL2", ""), "")
					api.SetToken(storeDetail.MtwmToken)
				} else {
					api = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, storeDetail.VendorOrgCode).(*mtwmapi.API)
				}

				for {
					foodList, _ := api.RetailListAll(storeDetail.VendorStoreID, i)
					for _, v := range foodList {
						//skuEx := &model.SkuExinfoMap{
						//	NameID:          storeId,
						//	ImgWatermark:    v.PictureList[0], // 原图
						//	ImgWatermarkMix: v.AppFoodCode,    // 商品ID
						//	ExPrefix:        exPrefix,
						//	VendorID:        vendorID,
						//	BeginAt:         fromTimeP,
						//	EndAt:           toTimeP,
						//	BrandID:         0,
						//}
						//dao.WrapAddIDCULDEntity(skuEx, ctx.GetUserName())
						//dao.CreateEntity(db, skuEx)

						param := map[string]interface{}{}
						qiNiuImg := ""
						ImgMix := ""
						if imgWaterMark != "" {
							qiNiuImg = jxutils.UploadQiNiuImg(v.PictureList[0])
							if ImgMix = jxutils.MixWatermarkImg2(imgWaterMark, qiNiuImg, &fromTimeP, &toTimeP); ImgMix != "" {
								picture := make([]string, 0, len(v.PictureList))
								picture = append(picture, ImgMix)
								if len(v.PictureList) > 1 {
									picture = append(picture, v.PictureList[1:]...)
								}
								param["picture"] = strings.Join(picture, ",")
							}
						}
						if exPrefix != "" {
							param["name"] = fmt.Sprintf("%s %s", exPrefix, v.Name)
						}
						if err = api.RetailInitData(utils.GetUUID(), storeDetail.VendorStoreID, v.AppFoodCode, param); err != nil {
							globals.SugarLogger.Debugf("------foodCode := %s ,err := %v param := %s", v.AppFoodCode, err, utils.Format4Output(params, false))
						}
						imgList = append(imgList, qiNiuImg, ImgMix)
						time.Sleep(100 * time.Microsecond)
					}
					if len(foodList) < 100 {
						break
					}
					i++
				}
				for _, v := range imgList {
					globals.SugarLogger.Debugf("-------v := %s", v)
					aa := strings.Split(v, "/")[3]
					globals.SugarLogger.Debugf("-------aa := %s", aa)
					jxutils.DeleteExportContent(aa)
					time.Sleep(100 * time.Microsecond)
				}
				//case model.VendorIDEBAI:
				//	api := api.EbaiAPI
				//	for {
				//		foodList, _ := api.RetailListAll(storeDetail.VendorStoreID, i)
				//		for _, v := range foodList {
				//			skuEx := &model.SkuExinfoMap{
				//				NameID:          storeId,
				//				ImgWatermark:    v.PictureList[0], // 原图
				//				ImgWatermarkMix: v.AppFoodCode,    // 商品ID
				//				ExPrefix:        exPrefix,
				//				VendorID:        vendorID,
				//				BeginAt:         fromTimeP,
				//				EndAt:           toTimeP,
				//				BrandID:         0,
				//			}
				//			dao.WrapAddIDCULDEntity(skuEx, ctx.GetUserName())
				//			dao.CreateEntity(db, skuEx)
				//
				//			param := map[string]interface{}{}
				//			qiNiuImg := ""
				//			ImgMix := ""
				//			if imgWaterMark != "" {
				//				qiNiuImg = jxutils.UploadQiNiuImg(v.PictureList[0])
				//				if ImgMix = jxutils.MixWatermarkImg2(imgWaterMark, qiNiuImg, &fromTimeP, &toTimeP); ImgMix != "" {
				//					picture := make([]string, 0, len(v.PictureList))
				//					picture = append(picture, ImgMix)
				//					if len(v.PictureList) > 1 {
				//						picture = append(picture, v.PictureList[1:]...)
				//					}
				//					param["picture"] = strings.Join(picture, ",")
				//				}
				//			}
				//			if exPrefix != "" {
				//				param["name"] = fmt.Sprintf("%s %s", exPrefix, v.Name)
				//			}
				//			if err = api.RetailInitData(utils.GetUUID(), storeDetail.VendorStoreID, v.AppFoodCode, param); err != nil {
				//				globals.SugarLogger.Debugf("------foodCode := %s ,err := %v param := %s", v.AppFoodCode, err, utils.Format4Output(params, false))
				//			}
				//			imgList = append(imgList, qiNiuImg, ImgMix)
				//			time.Sleep(100 * time.Microsecond)
				//		}
				//		if len(foodList) < 100 {
				//			break
				//		}
				//		i++
				//	}
				//	for _, v := range imgList {
				//		jxutils.DeleteExportContent(strings.Split(v, "/")[3])
				//		time.Sleep(100 * time.Microsecond)
				//	}

			}
			return retVal, err
		}, []int{1})
	tasksch.HandleTask(task, nil, true).Run()
	if isAsync {
		hint = task.GetID()
	} else {
		_, err = task.GetResult(0)
		hint = "1"
	}

	return hint, err
}

func GetVendorCategoryMap(ctx *jxcontext.Context, parentID, level, vendorID int, vendorOrgCode string) (vendorMaps []*model.VendorCategoryMap, err error) {
	db := dao.GetDB()
	vendorMaps, err = dao.GetVendorCategoryMap(db, parentID, level, vendorID, vendorOrgCode, 0)
	if err != nil {
		return nil, err
	}
	return vendorMaps, err
}

func AddVendorCategoryMap(ctx *jxcontext.Context, vendorCategoryMap *model.VendorCategoryMap) (result *model.VendorCategoryMap, err error) {
	var (
		db = dao.GetDB()
	)
	if vendorCategoryMap.Level != 1 {
		storeCatMaps, _ := dao.GetVendorCategoryMap(db, -1, 0, vendorCategoryMap.VendorID, vendorCategoryMap.VendorOrgCode, vendorCategoryMap.CategoryID)
		if len(storeCatMaps) > 0 {
			return nil, fmt.Errorf("已存在绑定的京西分类，分类名：[%v]", storeCatMaps[0].VendorCategoryName)
		}
	}
	vendorOrgCodes, _ := dao.GetVendorOrgCode(db, vendorCategoryMap.VendorID, vendorCategoryMap.VendorOrgCode, model.VendorOrgTypePlatform)
	vendorCategoryMap.VendorCategoryName = strings.Trim(vendorCategoryMap.VendorCategoryName, " ")
	dao.WrapAddIDCULDEntity(vendorCategoryMap, ctx.GetUserName())
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if err = dao.CreateEntity(db, vendorCategoryMap); err != nil {
		dao.Rollback(db, txDB)
		return nil, err
	}
	//如果传了京西绑定，要去thingmap里改同步标志
	if vendorCategoryMap.CategoryID != 0 {
		if err = OnCreateThing(ctx, db, vendorOrgCodes, int64(vendorCategoryMap.CategoryID), model.ThingTypeCategory, model.SyncFlagNewMask, true); err != nil {
			dao.Rollback(db, txDB)
			return nil, err
		}
	}
	dao.Commit(db, txDB)
	result = vendorCategoryMap
	if vendorCategoryMap.CategoryID != 0 {
		SyncCategories(ctx, nil, []int{vendorCategoryMap.VendorID}, []string{vendorCategoryMap.VendorOrgCode}, []int{vendorCategoryMap.CategoryID}, true)
		// _, err = CurVendorSync.SyncCategory(ctx, nil, vendorCategoryMap.CategoryID, false, ctx.GetUserName())
	}
	return result, err
}

func UpdateVendorCategoryMap(ctx *jxcontext.Context, ID int, vendorCategoryMap *model.VendorCategoryMap, isDelete bool) (num int64, err error) {
	var (
		db                 = dao.GetDB()
		valid              = make(map[string]interface{})
		vendorCategoryMap2 = &model.VendorCategoryMap{}
		vendorCategoryID   int
	)
	vendorCategoryMap2.ID = ID
	if err = dao.GetEntity(db, vendorCategoryMap2); err != nil {
		return 0, err
	}
	if vendorCategoryMap.VendorCategoryName != "" {
		valid["vendorCategoryName"] = vendorCategoryMap.VendorCategoryName
	}
	if vendorCategoryMap.CategoryID != 0 {
		valid["categoryID"] = vendorCategoryMap.CategoryID
		if !isDelete {
			storeCatMaps, _ := dao.GetVendorCategoryMap(db, -1, 0, vendorCategoryMap2.VendorID, vendorCategoryMap2.VendorOrgCode, vendorCategoryMap.CategoryID)
			if len(storeCatMaps) > 0 {
				for _, v := range storeCatMaps {
					if v.ID != ID {
						return 0, fmt.Errorf("已存在绑定的京西分类，分类名：[%v]", storeCatMaps[0].VendorCategoryName)
					}
				}
			}
		}
		vendorCategoryID = vendorCategoryMap.CategoryID
	} else {
		vendorCategoryID = vendorCategoryMap2.CategoryID
	}
	if vendorCategoryMap.Level != 0 {
		valid["level"] = vendorCategoryMap.Level
		if vendorCategoryMap.Level == 2 {
			cat2, _ := dao.GetCategories(db, -1, 0, []int{vendorCategoryMap.CategoryID}, false)
			if len(cat2) > 0 {
				if cat2[0].ParentID != vendorCategoryMap.ParentID {
					return 0, fmt.Errorf("此二级分类只能绑定到对应一级分类下！")

				}
			}
		}
	}
	if isDelete {
		valid["deletedAt"] = time.Now()
		valid["updatedAt"] = time.Now()
		valid["lastOperator"] = ctx.GetUserName()
		//如果是1级分类则删除下面的子分类
		var catIDs []int
		if vendorCategoryMap2.Level == 1 {
			storeCatMaps, _ := dao.GetVendorCategoryMap(db, vendorCategoryMap2.CategoryID, 2, vendorCategoryMap2.VendorID, vendorCategoryMap2.VendorOrgCode, 0)
			if len(storeCatMaps) > 0 {
				for _, v := range storeCatMaps {
					catIDs = append(catIDs, v.CategoryID)
					v.DeletedAt = time.Now()
					v.LastOperator = ctx.GetUserName()
					dao.UpdateEntity(db, v, "DeletedAt", "LastOperator")
				}
			}
		}
		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 = ?
		`, vendorCategoryMap2.CategoryID, utils.DefaultTimeValue, vendorCategoryMap2.CategoryID, utils.DefaultTimeValue, vendorCategoryMap2.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("还有商品类别使用此类别，不能删除")
			}
		}
	}
	vendorOrgCodes, err := dao.GetVendorOrgCode(db, vendorCategoryMap2.VendorID, vendorCategoryMap2.VendorOrgCode, model.VendorOrgTypePlatform)
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if num, err = dao.UpdateEntityLogically(db, vendorCategoryMap2, valid, ctx.GetUserName(), nil); err != nil {
		dao.Rollback(db, txDB)
		return 0, err
	}
	if err = OnUpdateThing(ctx, db, vendorOrgCodes, int64(vendorCategoryID), model.ThingTypeCategory); err != nil {
		dao.Rollback(db, txDB)
		return 0, err
	}
	dao.Commit(db, txDB)
	SyncCategories(ctx, nil, []int{vendorCategoryMap.VendorID}, []string{vendorCategoryMap.VendorOrgCode}, []int{vendorCategoryID}, true)
	return num, err
}

func ReorderVendorCategories(ctx *jxcontext.Context, parentID, vendorID int, vendorOrgCode string, categoryIDs []int) (err error) {
	var (
		vendorCatsMap []*model.VendorCategoryMap
	)
	db := dao.GetDB()
	vendorCatsMap, err = dao.GetVendorCategoryMap(db, parentID, 0, vendorID, vendorOrgCode, 0)
	catsLen := len(vendorCatsMap)
	if catsLen != len(categoryIDs) {
		return ErrInputCatsDoesntMatch
	}
	catsMap := make(map[int]*model.VendorCategoryMap, catsLen)
	for _, cat := range vendorCatsMap {
		catsMap[cat.CategoryID] = cat
	}
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	for k, v := range categoryIDs {
		if catsMap[v] == nil {
			dao.Rollback(db, txDB)
			return fmt.Errorf("分类:%d不在%d分类下", v, parentID)
		}
		catsMap[v].VendorCategorySeq = k
		catsMap[v].LastOperator = ctx.GetUserName()
		if _, err = dao.UpdateEntity(db, catsMap[v]); err != nil {
			dao.Rollback(db, txDB)
			return err
		}
	}
	dao.Commit(db, txDB)
	err = SyncReorderCategories2(ctx, parentID, vendorID, vendorOrgCode)
	return err
}

func LoadStoreVendorCategories(ctx *jxcontext.Context, vendorOrgCode string, vendorID, storeID int) (err error) {
	var (
		db = dao.GetDB()
	)

	storeCats, err := dao.GetStoreCategoryMap(db, -1, 0, storeID, 0)
	if len(storeCats) == 0 {
		return fmt.Errorf("未查询到该门店有门店分类，请重新选择！ [%v]", storeID)
	}
	vendorOrgCodes, _ := dao.GetVendorOrgCode(db, vendorID, vendorOrgCode, model.VendorOrgTypePlatform)
	if vendorCatMap, _ := dao.GetVendorCategoryMap(db, -1, 0, vendorID, vendorOrgCode, 0); len(vendorCatMap) > 0 {
		return fmt.Errorf("该账号下已有分类，请在这里修改！")
	}
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	sql := `
		DELETE FROM vendor_category_map WHERE vendor_id = ? AND vendor_org_code = ?
	`
	sqlParams := []interface{}{
		vendorID, vendorOrgCode,
	}
	if _, err = dao.ExecuteSQL(db, sql, sqlParams); err != nil {
		dao.Rollback(db, txDB)
		return err
	}
	sql2 := `
		INSERT INTO vendor_category_map
		(created_at, updated_at, last_operator, deleted_at, vendor_id, vendor_org_code, category_id, vendor_category_name, vendor_category_seq, level, parent_id,is_hidden)
		SELECT ?, ?, ?, ?, ?, ?, category_id, store_category_name, store_category_seq, level, parent_id,is_hidden 
		  FROM store_category_map 
		 WHERE deleted_at = ? 
		   AND store_id = ?
	`
	sqlParams2 := []interface{}{
		time.Now(), time.Now(), ctx.GetUserName(), utils.DefaultTimeValue,
		vendorID, vendorOrgCode,
		utils.DefaultTimeValue,
		storeID,
	}
	if _, err = dao.ExecuteSQL(db, sql2, sqlParams2); err != nil {
		dao.Rollback(db, txDB)
		return err
	}
	dao.Commit(db, txDB)
	catList, _ := dao.GetSkuCategoryWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, -1, nil, false)
	for _, v := range storeCats {
		if len(catList) > 0 {
			OnUpdateThing(ctx, db, vendorOrgCodes, int64(v.CategoryID), model.ThingTypeCategory)
		} else {
			OnCreateThing(ctx, db, vendorOrgCodes, int64(v.CategoryID), model.ThingTypeCategory, model.SyncFlagNewMask, true)
		}
	}
	if _, err = SyncCategories(ctx, nil, []int{vendorID}, []string{vendorOrgCode}, nil, false); err == nil {
		SyncReorderCategories2(ctx, 0, vendorID, vendorOrgCode)
	}
	return err
}

func RefreshNoImgSku(ctx *jxcontext.Context, skuNameID int) (err error) {
	var (
		db       = dao.GetDB()
		skuNames []*model.SkuName
	)
	sql := `
		SELECT * FROM sku_name WHERE deleted_at = ? AND upc <> '' AND img <> '' ORDER BY created_at DESC
	`
	sqlParams := []interface{}{
		utils.DefaultTimeValue,
	}
	if skuNameID > 0 {
		sql += " AND id = ?"
		sqlParams = append(sqlParams, skuNameID)
	}

	dao.GetRows(db, &skuNames, sql, sqlParams)
	//task := tasksch.NewParallelTask("uuuuu", tasksch.NewParallelConfig().SetParallelCount(20).SetIsContinueWhenError(true), ctx,
	//	func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
	for _, v := range skuNames {
		data, _, _ := jxutils.DownloadFileByURL(v.Img)
		if string(data) == "" {
			if v.Upc != nil {
				productInfos, _ := api.JdAPI.GetJdUpcCodeByName("", *v.Upc, 1, 30)
				if len(productInfos) > 0 {
					productInfo := productInfos[0]
					if len(productInfo.ImgList) >= 5 {
						v.Img = productInfo.ImgList[0]
						v.Img2 = productInfo.ImgList[1]
						v.Img3 = productInfo.ImgList[2]
						v.Img4 = productInfo.ImgList[3]
						v.Img5 = productInfo.ImgList[4]
					} else {
						result, _ := api.MtwmAPI.GetStandardProductListWithCond(*v.Upc)
						if result != nil {
							imgs := strings.Split(result.Pic, ",")
							if len(imgs) >= 5 {
								v.Img = imgs[0]
								v.Img2 = imgs[1]
								v.Img3 = imgs[2]
								v.Img4 = imgs[3]
								v.Img5 = imgs[4]
							} else {
								if len(imgs) > len(productInfo.ImgList) {
									setImgs2(v, imgs)
								} else {
									setImgs2(v, productInfo.ImgList)
								}
							}
						} else {
							setImgs2(v, productInfo.ImgList)
						}
					}
				} else {
					result, _ := api.MtwmAPI.GetStandardProductListWithCond(*v.Upc)
					if result != nil {
						imgs := strings.Split(result.Pic, ",")
						setImgs2(v, imgs)
					}
				}
				dao.UpdateEntity(db, v, "Img", "Img2", "Img3", "Img4", "Img5")
			}
		}
	}
	return err
}

func setImgs(v *model.SkuNameExt, imgs []string) (err error) {
	switch len(imgs) {
	case 0:
	case 1:
		v.Img = imgs[0]
	case 2:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
	case 3:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
		v.Img3 = imgs[2]
	case 4:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
		v.Img3 = imgs[2]
		v.Img4 = imgs[3]
	case 5:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
		v.Img3 = imgs[2]
		v.Img4 = imgs[3]
		v.Img5 = imgs[4]
	default:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
		v.Img3 = imgs[2]
		v.Img4 = imgs[3]
		v.Img5 = imgs[4]
	}
	return err
}

func setImgs2(v *model.SkuName, imgs []string) (err error) {
	switch len(imgs) {
	case 0:
	case 1:
		v.Img = imgs[0]
	case 2:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
	case 3:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
		v.Img3 = imgs[2]
	case 4:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
		v.Img3 = imgs[2]
		v.Img4 = imgs[3]
	case 5:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
		v.Img3 = imgs[2]
		v.Img4 = imgs[3]
		v.Img5 = imgs[4]
	default:
		v.Img = imgs[0]
		v.Img2 = imgs[1]
		v.Img3 = imgs[2]
		v.Img4 = imgs[3]
		v.Img5 = imgs[4]
	}
	return err
}

func GetSkuNamesNew(ctx *jxcontext.Context, keyword string, skuIDs, skuNameIDs []int, categoryID, status int, isBySku bool, offset, pageSize, bestSeller, maxPrice, minPrice int) (skuNamesInfo *SkuNamesInfo, err error) {
	var (
		db  = dao.GetDB()
		sql = ""
	)
	if !isBySku {
		sql = `
		SELECT
		SQL_CALC_FOUND_ROWS
		DISTINCT
		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.img3,
		t1.img4,
		t1.img5,
		t1.img_watermark,
		t1.img_mix,
		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,
		t1.jds_stock_switch,
		t1.preparation_time,
		t1.mt_attribute,
		t1.ebai_attribute,
		t1.qua_pictures,
		t1.qua_effective_date,
		t1.qua_approval_date,
		t1.special_pictures,
		t1.best_seller
		FROM sku_name t1
		LEFT JOIN sku t2 ON t1.id = t2.name_id AND t2.deleted_at = ?
		LEFT JOIN thing_map t3 ON t3.thing_id = t2.id AND t3.thing_type = ? AND t3.vendor_org_code = ? AND t3.deleted_at = ?
		WHERE t1.deleted_at = ?
	`
	} else {
		sql = `
		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.img3,
		t1.img4,
		t1.img5,
		t1.img_watermark,
		t1.img_mix,
		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,
		t1.jds_stock_switch,
		t1.preparation_time,
		t1.best_seller,		
		t1.mt_attribute,
		t1.ebai_attribute,
		t1.qua_pictures,
		t1.qua_effective_date,
		t1.qua_approval_date,
		t1.special_pictures,
		t2.id sku_id
		FROM sku_name t1
		LEFT JOIN sku t2 ON t1.id = t2.name_id AND t2.deleted_at = ?
		LEFT JOIN thing_map t3 ON t3.thing_id = t2.id AND t3.thing_type = ? AND t3.vendor_org_code = ? AND t3.deleted_at = ? 
		WHERE t1.deleted_at = ?
	`
	}
	sqlParams := []interface{}{
		utils.DefaultTimeValue, utils.DefaultTimeValue, model.ThingTypeSku, "320406", utils.DefaultTimeValue,
	}
	if keyword != "" {
		keywordLike := "%" + keyword + "%"
		sql += `
			AND (t1.name LIKE ? OR t1.prefix LIKE ? OR t2.comment LIKE ? OR t1.upc LIKE ? OR t1.id LIKE ? OR t2.id LIKE ? OR t3.vendor_thing_id LIKE ?) `
		sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike)
	}
	if len(skuNameIDs) > 0 {
		sql += " AND t1.id IN (" + dao.GenQuestionMarks(len(skuNameIDs)) + ")"
		sqlParams = append(sqlParams, skuNameIDs)
	}

	if len(skuIDs) > 0 {
		sql += " AND t2.id IN (" + dao.GenQuestionMarks(len(skuIDs)) + ")"
		sqlParams = append(sqlParams, skuIDs)
	}
	if bestSeller > 0 {
		sql += " AND t1.best_seller = ? "
		sqlParams = append(sqlParams, bestSeller)
	}
	if minPrice > 0 {
		sql += " AND t1.price >= ? "
		sqlParams = append(sqlParams, minPrice)
	}
	if maxPrice > 0 {
		sql += " AND t1.price <= ? "
		sqlParams = append(sqlParams, maxPrice)
	}
	if categoryID > 0 {
		cat := &model.SkuCategory{}
		cat.ID = categoryID
		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 status != -1 {
		sql += " AND t2.status = ? "
		sqlParams = append(sqlParams, status)
	}

	sql += `
	ORDER BY t1.id DESC 
	LIMIT ? OFFSET ?`
	pageSize = jxutils.FormalizePageSize(pageSize)
	offset = jxutils.FormalizePageOffset(offset)
	sqlParams = append(sqlParams, pageSize, offset)
	skuNamesInfo = &SkuNamesInfo{}
	txDB, _ := dao.Begin(db) // todo 这里用事务的原因是，SQL_CALC_FOUND_ROWS会出错
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if err = dao.GetRowsTx(txDB, &skuNamesInfo.SkuNames, sql, sqlParams...); err == nil {
		skuNamesInfo.TotalCount = dao.GetLastTotalRowCount2(db, txDB)
		dao.Commit(db, txDB)
		task := tasksch.NewParallelTask("GetSkuNamesNew", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
			func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
				skuName := batchItemList[0].(*model.SkuNameExt)
				skuName.FullName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, "", "", 0, "", 0, skuName.ExPrefix, skuName.ExPrefixBegin, skuName.ExPrefixEnd)
				var (
					skus      []*model.Sku
					sqlParams = []interface{}{utils.DefaultTimeValue}
					sql       string
				)
				if !isBySku {
					sql = `
					SELECT * FROM sku WHERE deleted_at = ? AND name_id = ?
				`
					sqlParams = append(sqlParams, skuName.ID)
				} else {
					sql = `
					SELECT * FROM sku WHERE deleted_at = ? AND id = ?
				`
					sqlParams = append(sqlParams, skuName.SkuID)
				}
				if err = dao.GetRows(db, &skus, sql, sqlParams); err == nil {
					var skusVendors []*model.SkuWithVendor
					for _, v := range skus {
						var things []*model.ThingMap
						sql := `
							SELECT * FROM thing_map WHERE  thing_id = ? AND vendor_thing_id <> "" AND thing_type = ? AND vendor_org_code IN (?,?,?) AND deleted_at = ?
						`
						sqlParams := []interface{}{v.ID, model.ThingTypeSku, "320406", "379599", "390558", utils.DefaultTimeValue} // 京东到家菜市,果切,宠物
						dao.GetRows(db, &things, sql, sqlParams)
						skusVendor := &model.SkuWithVendor{
							Sku:     v,
							MapList: things,
						}
						skusVendors = append(skusVendors, skusVendor)
					}
					skuName.Skus = skusVendors
				}
				var (
					places     []*model.SkuNamePlaceBind
					placeCodes []int
				)
				sql2 := `
				SELECT * FROM sku_name_place_bind WHERE name_id = ?
			`
				sqlParams2 := []interface{}{skuName.ID}
				if err = dao.GetRows(db, &places, sql2, sqlParams2); err == nil {
					for _, v := range places {
						placeCodes = append(placeCodes, v.PlaceCode)
					}
					skuName.Places = placeCodes
				}

				// 京西商品库页面只获取美团属性来作为判断值,其余平台暂不获取
				skuVendorCats, _ := dao.GetSkuVendorCategoryMaps(db, []int{skuName.ID}, []int{model.VendorIDMTWM}, nil)
				if len(skuVendorCats) > 0 {
					for _, v := range skuVendorCats {
						if v.VendorID == model.VendorIDMTWM {
							skuName.MtwmCategoryID = v.VendorCategoryID
							break
						}
						//if v.VendorID == model.VendorIDJDShop {
						//	skuName.JdsCategoryID = v.VendorCategoryID
						//}
						//if v.VendorID == model.VendorIDDD {
						//	skuName.DdCategoryID = v.VendorCategoryID
						//}
						//if v.VendorID == model.VendorIDJD {
						//	skuName.JdCategoryID = v.VendorCategoryID
						//}
						//if v.VendorID == model.VendorIDEBAI {
						//	skuName.EbaiCategoryID = v.VendorCategoryID
						//}
					}
				}

				return retVal, err
			}, skuNamesInfo.SkuNames)
		tasksch.HandleTask(task, nil, true).Run()
		task.GetResult(0)
	}
	return skuNamesInfo, err
}

func SetSkuNameSeller(nameIds []int64, bastSeller int) error {
	sql := ` UPDATE sku_name SET bast_seller = ? WHERE id IN (` + dao.GenQuestionMarks(len(nameIds)) + `)`
	param := []interface{}{bastSeller, nameIds}
	_, err := dao.ExecuteSQL(dao.GetDB(), sql, param...)
	return err
}
