Files
jx-callback/business/jxstore/cms/sku.go
2018-09-20 10:07:58 +08:00

532 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cms
import (
"errors"
"strconv"
"strings"
"git.rosy.net.cn/baseapi/utils"
"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"
)
type SkuNamesInfo struct {
TotalCount int `json:"totalCount"`
SkuNames []*model.SkuNameExt `json:"skuNames"`
}
var (
ErrInputCatsDoesntMatch = errors.New("输入的类别列表不合法需要输入一个父ID下的所有子类别")
)
// parentID 为-1表示所有
func GetVendorCategories(vendorID int, parentID string) (vendorCats []*model.SkuVendorCategory, err error) {
cond := map[string]interface{}{
model.FieldVendorID: vendorID,
}
if parentID != "-1" {
cond[model.FieldParentID] = parentID
}
return vendorCats, dao.GetEntitiesByKV(nil, &vendorCats, cond, false)
}
// parentID 为-1表示所有
func GetCategories(parentID int) (cats []*model.SkuCategory, err error) {
params := []interface{}{}
sql := "SELECT * FROM sku_category WHERE deleted_at = '1970-01-01 00:00:00' "
if parentID != -1 {
sql += " AND parent_id = ?"
params = append(params, parentID)
}
sql += " ORDER BY level, seq"
return cats, dao.GetRows(nil, &cats, sql, params)
}
func AddCategory(cat *model.SkuCategory, userName string) (outCat *model.SkuCategory, err error) {
dao.WrapAddIDCULDEntity(cat, userName)
cat.JdSyncStatus = model.SyncFlagNewMask
cat.JdID = genTmpID()
if err = dao.CreateEntity(nil, cat); err == nil {
outCat = cat
err = CurVendorSync.SyncCategory(nil, cat.ID, false, userName)
}
return outCat, err
}
func UpdateCategory(categoryID int, payload map[string]interface{}, userName string) (num int64, err error) {
cat := &model.SkuCategory{}
cat.ID = categoryID
valid := dao.NormalMakeMapByStructObject(payload, cat, userName)
if len(valid) > 0 {
valid[model.FieldJdSyncStatus] = model.SyncFlagModifiedMask
db := dao.GetDB()
if num, err = dao.UpdateEntityLogically(db, cat, valid, userName, nil); err == nil {
err = CurVendorSync.SyncCategory(db, categoryID, false, userName)
}
}
return num, err
}
func ReorderCategories(parentID int, categoryIDs []int, userName string) (err error) {
var cats []*model.SkuCategory
parentCat := &model.SkuCategory{}
parentCat.ID = parentID
db := dao.GetDB()
if parentID != 0 {
err = dao.GetEntity(db, parentCat)
} else {
parentCat = nil
}
if err == nil {
if err = dao.GetEntitiesByKV(db, &cats, utils.Params2Map(model.FieldParentID, parentID), false); err == nil {
catsLen := len(cats)
if catsLen != len(categoryIDs) {
return ErrInputCatsDoesntMatch
}
catsMap := make(map[int]*model.SkuCategory, catsLen)
for _, cat := range cats {
catsMap[cat.ID] = cat
}
for k, v := range categoryIDs {
catsMap[v].Seq = (k + 1) * 5
// catsMap[v].JdSyncStatus = model.SyncFlagModifiedMask
if _, err = dao.UpdateEntity(db, catsMap[v], "Seq"); err != nil {
break
}
}
// todo 这里应该也需要先置标记
if err == nil {
if handler := GetPurchaseHandler(model.VendorIDJD); handler != nil {
err = handler.(partner.IMultipleStoresHandler).ReorderCategories(parentCat, userName)
}
}
}
}
return err
}
func DeleteCategory(categoryID int, isForce bool, 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 = ?
UNION ALL
SELECT COUNT(*) ct
FROM sku_name t1
WHERE t1.category_id = ?
UNION ALL
SELECT COUNT(*) ct
FROM sku_category t1
WHERE t1.parent_id = ?
`, categoryID, categoryID, categoryID, &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("还有商品类别使用此类别,不能删除")
}
if num, err = dao.DeleteEntityLogically(db, cat, utils.Params2Map(model.FieldJdSyncStatus, model.SyncFlagDeletedMask), userName, nil); err == nil && num == 1 {
err = CurVendorSync.SyncCategory(db, cat.ID, false, userName)
}
}
return num, err
}
func GetSkuNames(keyword string, 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 = '1970-01-01 00:00:00'
LEFT JOIN sku_name_place_bind t3 ON t1.id = t3.name_id
WHERE t1.deleted_at = '1970-01-01 00:00:00'`
sqlParams := make([]interface{}, 0)
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += " AND (t1.name LIKE ? OR t1.prefix LIKE ? OR t1.comment LIKE ?"
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike)
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
sql += " OR t2.jd_id = ? OR t1.id = ? OR t1.category_id = ?"
sqlParams = append(sqlParams, keywordInt64, keywordInt64, keywordInt64)
}
sql += ")"
}
if params["nameID"] != nil {
sql += " AND t1.id = ?"
sqlParams = append(sqlParams, params["nameID"].(int))
}
if params["categoryID"] != nil {
cat := &model.SkuCategory{}
cat.ID = params["categoryID"].(int)
if err = dao.GetEntity(db, cat); err != nil {
return nil, err
}
if cat.Level == 1 {
sql += " AND t1.category_id IN (SELECT id FROM sku_category WHERE parent_id = ?)"
} else {
sql += " AND t1.category_id = ?"
}
sqlParams = append(sqlParams, cat.ID)
}
if params["jdID"] != nil {
sql += " AND t1.jd_id = ?"
sqlParams = append(sqlParams, params["jdID"].(int))
}
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["fromStatus"] != nil {
fromStatus := params["fromStatus"].(int)
toStatus := fromStatus
if params["toStatus"] != nil {
toStatus = params["toStatus"].(int)
}
sql += " AND t2.status >= ? AND t2.status <= ?"
sqlParams = append(sqlParams, fromStatus, toStatus)
}
sql += `
GROUP BY
t1.id,
t1.created_at,
t1.updated_at,
t1.last_operator,
t1.deleted_at,
t1.prefix,
t1.name,
t1.comment,
t1.brand_id,
t1.category_id,
t1.is_global,
t1.unit,
t1.price,
t1.img,
t1.elm_img_hash_code
`
sqlData := `
SELECT
SQL_CALC_FOUND_ROWS
t1.id,
t1.created_at,
t1.updated_at,
t1.last_operator,
t1.deleted_at,
t1.prefix,
t1.name,
t1.comment,
t1.brand_id,
t1.category_id,
t1.is_global,
t1.unit,
t1.price,
t1.img,
t1.elm_img_hash_code,
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"id":', t2.id, ',"status":', t2.status, ',"createdAt":"', CONCAT(REPLACE(t2.created_at," ","T"),"+08:00"), '","updatedAt":"', CONCAT(REPLACE(t2.updated_at," ","T"),"+08:00"), '","lastOperator":"', t2.last_operator, '","specQuality":', t2.spec_quality, ',"specUnit":"', t2.spec_unit, '","weight":', t2.weight, ',"jdID":', t2.jd_id, ',"categoryID":', t2.category_id, ',"nameID":', t2.name_id, "}")), "]") skus_str,
CONCAT("[", GROUP_CONCAT(DISTINCT t3.place_code), "]") places_str
` + sql + `
ORDER BY t1.id
LIMIT ? OFFSET ?`
if pageSize == 0 {
pageSize = model.DefPageSize
}
if offset < 0 {
offset = 0
}
sqlParams = append(sqlParams, pageSize, offset)
skuNamesInfo = &SkuNamesInfo{}
dao.Begin(db) // todo 这里用事务的原因是SQL_CALC_FOUND_ROWS会出错
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if err = dao.GetRows(db, &skuNamesInfo.SkuNames, sqlData, sqlParams...); err == nil {
countInfo := &struct{ Ct int }{}
if err = dao.GetRow(db, countInfo, "SELECT FOUND_ROWS() ct"); err == nil {
skuNamesInfo.TotalCount = countInfo.Ct
for _, skuName := range skuNamesInfo.SkuNames {
if skuName.SkusStr != "" {
if err = utils.UnmarshalUseNumber([]byte(skuName.SkusStr), &skuName.Skus); err != nil {
break
}
}
if skuName.PlacesStr != "" {
if err = utils.UnmarshalUseNumber([]byte(skuName.PlacesStr), &skuName.Places); err != nil {
break
}
}
}
}
}
dao.Commit(db)
return skuNamesInfo, err
}
func AddSkuName(skuNameExt *model.SkuNameExt, userName string) (outSkuNameExt *model.SkuNameExt, err error) {
if skuNameExt.CategoryID == 0 {
return nil, errors.New("CategoryID不能为空")
}
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
dao.WrapAddIDCULDEntity(&skuNameExt.SkuName, userName)
if err = dao.CreateEntity(db, &skuNameExt.SkuName); err != nil {
dao.Rollback(db)
return nil, err
}
for _, sku := range skuNameExt.Skus {
dao.WrapAddIDCULDEntity(sku, userName)
sku.NameID = skuNameExt.ID
sku.JdSyncStatus = model.SyncFlagNewMask
sku.JdID = genTmpID()
if err = dao.CreateEntity(db, sku); err != nil {
dao.Rollback(db)
return nil, err
}
}
for _, placeCode := range skuNameExt.Places {
placeBind := &model.SkuNamePlaceBind{}
dao.WrapAddIDCULEntity(placeBind, userName)
placeBind.NameID = skuNameExt.ID
placeBind.PlaceCode = placeCode
if err = dao.CreateEntity(db, placeBind); err != nil {
dao.Rollback(db)
return nil, err
}
}
dao.Commit(db)
tmpInfo, err := GetSkuNames("", 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(db, outSkuNameExt.SkuName.ID, -1, false, userName)
return outSkuNameExt, err
}
func UpdateSkuName(nameID int, payload map[string]interface{}, userName string) (num int64, err error) {
var err2 error
skuName := &model.SkuName{}
skuName.ID = nameID
valid := dao.NormalMakeMapByStructObject(payload, skuName, userName)
if len(valid) > 0 {
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if num, err = dao.UpdateEntityLogically(db, skuName, valid, userName, nil); err == nil && num == 1 {
if utils.Interface2Int64WithDefault(payload["isGlobal"], 0) == 0 && payload["places"] != nil {
if places, ok := payload["places"].([]interface{}); ok {
if _, err = dao.ExecuteSQL(db, "DELETE FROM sku_name_place_bind WHERE name_id = ?", nameID); err == nil {
for _, placeCode := range places {
placeBind := model.SkuNamePlaceBind{}
placeBind.PlaceCode = int(utils.Interface2Int64WithDefault(placeCode, 0))
if placeBind.PlaceCode > 0 {
dao.WrapAddIDCULEntity(placeBind, userName)
placeBind.NameID = nameID
err = dao.CreateEntity(db, placeBind)
} else {
dao.Rollback(db)
return 0, errors.New("地点代码非法")
}
}
}
}
}
if err == nil {
sku := &model.Sku{}
_, err2 := dao.UpdateEntityLogically(db, sku, map[string]interface{}{
model.FieldJdSyncStatus: model.SyncFlagModifiedMask,
}, userName, map[string]interface{}{
model.FieldNameID: nameID,
})
if err = err2; err == nil {
dao.Commit(db)
err2 = CurVendorSync.SyncSku(db, nameID, -1, false, userName)
}
}
}
if err != nil {
dao.Rollback(db)
} else {
err = err2
}
}
return num, err
}
func DeleteSkuName(nameID int, userName string) (num int64, err error) {
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
skuName := &model.SkuName{}
skuName.ID = nameID
if num, err = dao.DeleteEntityLogically(db, skuName, nil, userName, nil); err == nil && num == 1 {
dummy := &model.Sku{}
num2, err2 := dao.DeleteEntityLogically(db, dummy, map[string]interface{}{
model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
model.FieldStatus: model.SkuStatusDeleted,
}, userName, map[string]interface{}{
model.FieldNameID: nameID,
})
if err2 == nil {
dao.Commit(db)
if num2 > 0 {
err = CurVendorSync.SyncSku(db, skuName.ID, -1, false, userName)
}
return num, err
}
}
dao.Rollback(db)
return num, err
}
func AddSku(nameID int, sku *model.Sku, userName string) (outSkuNameExt *model.SkuNameExt, err error) {
db := dao.GetDB()
dao.WrapAddIDCULDEntity(sku, userName)
sku.JdSyncStatus = model.SyncFlagNewMask
sku.NameID = nameID
sku.JdID = genTmpID()
if err = dao.CreateEntity(db, sku); err == nil {
result, err2 := GetSkuNames("", utils.Params2Map("skuID", sku.ID), 0, 0)
if err = err2; err == nil {
if result.TotalCount == 1 {
outSkuNameExt = result.SkuNames[0]
err = CurVendorSync.SyncSku(db, outSkuNameExt.SkuName.ID, sku.ID, false, userName)
} else {
err = ErrEntityNotExist
}
}
}
return outSkuNameExt, err
}
func UpdateSku(skuID int, payload map[string]interface{}, userName string) (num int64, err error) {
sku := &model.Sku{}
sku.ID = skuID
valid := dao.NormalMakeMapByStructObject(payload, sku, userName)
if len(valid) > 0 {
valid[model.FieldJdSyncStatus] = model.SyncFlagModifiedMask
db := dao.GetDB()
if num, err = dao.UpdateEntityLogically(db, sku, valid, userName, nil); err == nil {
if num == 1 {
err = CurVendorSync.SyncSku(db, -1, sku.ID, false, userName)
} else {
err = ErrEntityNotExist
}
}
}
return num, err
}
func DeleteSku(skuID int, userName string) (num int64, err error) {
db := dao.GetDB()
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 {
if num == 1 {
err = CurVendorSync.SyncSku(db, -1, sku.ID, false, userName)
} else {
err = ErrEntityNotExist
}
}
return num, err
}
func AddSkuNamePlace(nameID, placeCode int, userName string) (outPlaceBind *model.SkuNamePlaceBind, err error) {
db := dao.GetDB()
placeBind := &model.SkuNamePlaceBind{
NameID: nameID,
PlaceCode: placeCode,
}
dao.WrapAddIDCULEntity(placeBind, userName)
if err = dao.CreateEntity(db, placeBind); err == nil {
err = CurVendorSync.SyncSku(db, nameID, -1, false, userName)
}
return placeBind, err
}
func DeleteSkuNamePlace(nameID, placeCode int, userName string) (num int64, err error) {
db := dao.GetDB()
placeBind := &model.SkuNamePlaceBind{}
placeBind.NameID = nameID
placeBind.PlaceCode = placeCode
if num, err = dao.DeleteEntity(db, placeBind, model.FieldNameID, model.FieldPlaceCode); err == nil {
if num == 1 {
err = CurVendorSync.SyncSku(db, nameID, -1, false, userName)
} else {
err = ErrEntityNotExist
}
}
return num, err
}
func GetVendorSku(vendorID int, vendorSkuID string) (skuNameInfo *model.SkuNameExt, err error) {
if handler := GetPurchaseHandler(vendorID); handler != nil {
return handler.(partner.IMultipleStoresHandler).ReadSku(vendorSkuID)
}
return nil, ErrCanNotFindVendor
}