Files
jx-callback/business/jxstore/cms/store_sku.go
2018-10-16 15:01:59 +08:00

552 lines
17 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 (
"fmt"
"strconv"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
)
const (
CopyStoreSkuModeFresh = "fresh"
CopyStoreSkuModeUpdate = "update"
// CopyStoreSkuModeAdd = "add"
)
// GetStoreSkus用
type StoreSkuNameExt struct {
model.SkuName
UnitPrice int `json:"unitPrice"`
Skus []map[string]interface{} `orm:"-" json:"skus"`
SkusStr string `json:"-"`
}
// GetStoreSkus用
type StoreSkuNamesInfo struct {
TotalCount int `json:"totalCount"`
SkuNames []*StoreSkuNameExt `json:"skuNames"`
}
// UpdateStoreSku用API调用时
type StoreSkuBindSkuInfo struct {
SkuID int `json:"skuID"`
IsSale int `json:"isSale"` // -1不可售0忽略1可售
ElmID int64 `json:"elmID"`
EbaiID int64 `json:"ebaiID"`
}
// UpdateStoreSku用API调用时
type StoreSkuBindInfo struct {
NameID int `json:"nameID"`
UnitPrice int `json:"unitPrice"`
IsFocus int `json:"isFocus"` // -1不关注0忽略1关注
SubStoreID int `json:"subStoreID"`
Skus []*StoreSkuBindSkuInfo `json:"skus"`
}
type tStoreSkuBindAndSpec struct {
model.StoreSkuBind
SpecQuality float32
SpecUnit string
SkuNamePrice int
SkuNameUnit string
RealSkuID int `orm:"column(real_sku_id)"`
}
func GetStoreSkus(storeID int, isFocus bool, keyword string, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *StoreSkuNamesInfo, err error) {
db := dao.GetDB()
sql := `
FROM sku_name t1
JOIN sku t2 ON t1.id = t2.name_id AND t2.deleted_at = '1970-01-01 00:00:00' AND t2.status = ?
LEFT JOIN store_sku_bind t4 ON t4.sku_id = t2.id AND t4.deleted_at = '1970-01-01 00:00:00' AND t4.store_id = ?
JOIN store t3 ON t3.id = ?
LEFT JOIN sku_name_place_bind t5 ON t1.id = t5.name_id AND t3.city_code = t5.place_code
WHERE t1.deleted_at = '1970-01-01 00:00:00' AND (t1.is_global = 1 OR t5.id IS NOT NULL OR t4.status = ?)
`
if isFocus {
sql += " AND t4.sku_id IS NOT NULL"
} else {
sql += " AND t4.sku_id IS NULL"
}
sqlParams := []interface{}{
model.SkuStatusNormal,
storeID,
storeID,
model.SkuStatusNormal,
}
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 t4.id = ?"
sqlParams = append(sqlParams, 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 params["skuID"] != nil {
skuID, ok := params["skuID"].(int)
if ok {
sql += " AND t2.id = ?"
sqlParams = append(sqlParams, skuID)
} else {
skuIDs := params["skuID"].([]interface{})
sql += " AND t2.id IN (" + dao.GenQuestionMarks(len(skuIDs)) + ")"
sqlParams = append(sqlParams, skuIDs)
}
}
if isFocus && params["fromStatus"] != nil {
fromStatus := params["fromStatus"].(int)
toStatus := fromStatus
if params["toStatus"] != nil {
toStatus = params["toStatus"].(int)
}
sql += " AND t4.status >= ? AND t4.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(IF(t4.created_at IS NULL, '1970-01-01 00:00:00', t4.created_at)," ","T"),"+08:00"), '","updatedAt":"', CONCAT(REPLACE(IF(t4.updated_at IS NULL, '1970-01-01 00:00:00', t4.updated_at)," ","T"),"+08:00"),
'","lastOperator":"', IF(t4.last_operator IS NULL, '', t4.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, ',"subStoreID":', IF(t4.sub_store_id IS NULL, 0, t4.sub_store_id),
',"price":', IF(t4.price IS NULL, 0, t4.price), ',"unitPrice":', IF(t4.unit_price IS NULL, t1.price, t4.unit_price),
',"storeSkuStatus":', IF(t4.status IS NULL, 0, t4.status), "}")), "]") skus_str
` + sql + `
ORDER BY t1.id
LIMIT ? OFFSET ?`
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
skuNamesInfo = &StoreSkuNamesInfo{}
// globals.SugarLogger.Debug(sqlData)
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
// globals.SugarLogger.Debug(sqlData, sqlParams)
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 len(skuName.Skus) > 0 {
skuName.UnitPrice = int(utils.MustInterface2Int64(skuName.Skus[0]["unitPrice"]))
for _, v := range skuName.Skus {
delete(v, "unitPrice")
}
} else {
skuName.UnitPrice = skuName.Price
}
}
}
}
}
dao.Commit(db)
return skuNamesInfo, err
}
func UpdateStoreSku(storeID int, skuBindInfo *StoreSkuBindInfo, userName string) (num int64, err error) {
return UpdateStoreSkus(storeID, []*StoreSkuBindInfo{skuBindInfo}, userName)
}
func UpdateStoreSkus(storeID int, skuBindInfos []*StoreSkuBindInfo, userName string) (num int64, err error) {
skuIDs, err := updateStoreSkusWithoutSync(storeID, skuBindInfos, userName)
if err == nil {
db := dao.GetDB()
_, err = CurVendorSync.SyncStoresSkus(db, nil, []int{storeID}, skuIDs, false, userName)
return int64(len(skuIDs)), err
}
return 0, err
}
func updateStoreSkusWithoutSync(storeID int, skuBindInfos []*StoreSkuBindInfo, userName string) (needSyncSkus []int, err error) {
var num int64
db := dao.GetDB()
needSyncIDMap := make(map[int]int)
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
for _, skuBindInfo := range skuBindInfos {
inSkuBinds := skuBindInfo.Skus
var allBinds []*tStoreSkuBindAndSpec
if err = dao.GetRows(db, &allBinds, `
SELECT t2.*, t1.id real_sku_id, t1.spec_quality, t1.spec_unit, t3.price sku_name_price, t3.unit sku_name_unit
FROM sku t1
LEFT JOIN store_sku_bind t2 ON t2.sku_id = t1.id AND store_id = ? AND t2.deleted_at = ?
JOIN sku_name t3 ON t1.name_id = t3.id AND t3.deleted_at = ?
WHERE t1.name_id = ? AND t1.deleted_at = ?
`, storeID, utils.DefaultTimeValue, utils.DefaultTimeValue, skuBindInfo.NameID, utils.DefaultTimeValue); err == nil {
// globals.SugarLogger.Debug(len(allBinds))
inSkuBinsMap := make(map[int]*StoreSkuBindSkuInfo, len(inSkuBinds))
for _, v := range inSkuBinds {
inSkuBinsMap[v.SkuID] = v
}
unitPrice := 0
if skuBindInfo.UnitPrice != 0 {
unitPrice = skuBindInfo.UnitPrice
} else {
unitPrice = allBinds[0].UnitPrice
if unitPrice == 0 {
unitPrice = allBinds[0].SkuNamePrice
}
}
for _, v := range allBinds {
inSkuBind := inSkuBinsMap[v.SkuID]
var skuBind *model.StoreSkuBind
// globals.SugarLogger.Debug(ok)
if v.ID == 0 {
if skuBindInfo.IsFocus == 1 {
skuBind = &model.StoreSkuBind{
StoreID: storeID,
SkuID: v.RealSkuID,
SubStoreID: skuBindInfo.SubStoreID, // todo 这个应该从用户信息中自动获得
UnitPrice: unitPrice,
Price: jxutils.CaculateSkuPrice(unitPrice, v.SpecQuality, v.SpecUnit, v.SkuNameUnit),
Status: model.StoreSkuBindStatusDontSale, // 缺省不可售?
}
if inSkuBind != nil && inSkuBind.IsSale == 1 {
skuBind.Status = model.StoreSkuBindStatusNormal
}
setStoreSkuBindStatus(skuBind, model.SyncFlagNewMask)
dao.WrapAddIDCULDEntity(skuBind, userName)
globals.SugarLogger.Debug(utils.Format4Output(skuBind, false))
if err = dao.CreateEntity(db, skuBind); err != nil {
dao.Rollback(db)
return nil, err
}
num = 1
}
} else {
skuBind = &v.StoreSkuBind
if skuBindInfo.IsFocus == -1 {
if num, err = dao.DeleteEntityLogically(db, skuBind, map[string]interface{}{
model.FieldStatus: model.StoreSkuBindStatusDeleted,
model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
model.FieldElmSyncStatus: model.SyncFlagDeletedMask,
model.FieldEbaiSyncStatus: model.SyncFlagDeletedMask,
}, userName, nil); err != nil {
dao.Rollback(db)
return nil, err
}
} else {
needUpdate := false
if skuBindInfo.IsFocus == 1 {
skuBind.Status = model.StoreSkuBindStatusDontSale // 缺省不可售?
skuBind.DeletedAt = utils.DefaultTimeValue
needUpdate = true
}
if inSkuBind != nil && inSkuBind.IsSale != 0 {
if inSkuBind.IsSale == 1 {
skuBind.Status = model.StoreSkuBindStatusNormal
} else {
skuBind.Status = model.StoreSkuBindStatusDontSale
}
setStoreSkuBindStatus(skuBind, model.SyncFlagSaleMask)
needUpdate = true
}
if skuBindInfo.UnitPrice != 0 { // 这里是否需要加此条件限制
skuBind.UnitPrice = unitPrice
skuBind.Price = jxutils.CaculateSkuPrice(unitPrice, v.SpecQuality, v.SpecUnit, v.SkuNameUnit)
setStoreSkuBindStatus(skuBind, model.SyncFlagPriceMask)
needUpdate = true
}
if inSkuBind != nil && inSkuBind.EbaiID != 0 {
skuBind.EbaiID = inSkuBind.EbaiID
needUpdate = true
}
if inSkuBind != nil && inSkuBind.ElmID != 0 {
skuBind.ElmID = inSkuBind.ElmID
needUpdate = true
}
if needUpdate {
setStoreSkuBindStatus(skuBind, model.SyncFlagModifiedMask)
dao.WrapUpdateULEntity(skuBind, userName)
if num, err = dao.UpdateEntity(db, skuBind); err != nil {
dao.Rollback(db)
return nil, err
}
}
}
if skuBind != nil && num == 1 {
needSyncIDMap[skuBind.ID] = 1
}
}
}
} else {
dao.Rollback(db)
return nil, err
}
}
dao.Commit(db)
skuIDs := jxutils.IntMap2List(needSyncIDMap)
return skuIDs, err
}
func UpdateStoresSkus(storeIDs []int, skuBindInfos []*StoreSkuBindInfo, userName string) (num int64, err error) {
for _, storeID := range storeIDs {
skuIDs, err2 := updateStoreSkusWithoutSync(storeID, skuBindInfos, userName)
if err = err2; err != nil {
return 0, err
}
num += int64(len(skuIDs))
}
skuIDs := make([]int, 0)
for _, v := range skuBindInfos {
for _, v2 := range v.Skus {
skuIDs = append(skuIDs, v2.SkuID)
}
}
db := dao.GetDB()
_, err = CurVendorSync.SyncStoresSkus(db, nil, storeIDs, skuIDs, false, userName)
return num, err
}
func updateStoreSkusSaleWithoutSync(storeID int, skuBindSkuInfos []*StoreSkuBindSkuInfo, userName string) (needSyncSkus []int, err error) {
var num int64
db := dao.GetDB()
needSyncIDMap := make(map[int]int)
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
for _, v := range skuBindSkuInfos {
if v.IsSale != 0 {
skuBind := &model.StoreSkuBind{}
if v.IsSale == 1 {
skuBind.Status = model.StoreSkuBindStatusNormal
} else {
skuBind.Status = model.StoreSkuBindStatusDontSale
}
if num, err = dao.UpdateEntityLogically(db, skuBind, map[string]interface{}{
model.FieldStatus: skuBind.Status,
}, userName, map[string]interface{}{
model.FieldStoreID: storeID,
model.FieldSkuID: v.SkuID,
}); err != nil {
dao.Rollback(db)
return nil, err
}
if num == 1 {
needSyncIDMap[v.SkuID] = 1
}
}
}
dao.Commit(db)
needSyncSkus = jxutils.IntMap2List(needSyncIDMap)
return needSyncSkus, err
}
func UpdateStoresSkusSale(storeIDs []int, skuBindSkuInfos []*StoreSkuBindSkuInfo, userName string) (num int64, err error) {
for _, storeID := range storeIDs {
skuIDs, err2 := updateStoreSkusSaleWithoutSync(storeID, skuBindSkuInfos, userName)
if err = err2; err != nil {
return 0, err
}
num += int64(len(skuIDs))
}
skuIDs := make([]int, 0)
for _, v := range skuBindSkuInfos {
skuIDs = append(skuIDs, v.SkuID)
}
db := dao.GetDB()
_, err = CurVendorSync.SyncStoresSkus(db, nil, storeIDs, skuIDs, false, userName)
return num, err
}
func CopyStoreSkus(fromStoreID, toStoreID int, copyMode string, params map[string]interface{}, userName string) (num int64, err error) {
if copyMode != CopyStoreSkuModeFresh && copyMode != CopyStoreSkuModeUpdate {
return 0, fmt.Errorf("不支持的拷贝模式:%s", copyMode)
}
db := dao.GetDB()
sqlCatAndSku := ""
sqlCatAndSkuParams := make([]interface{}, 0)
if params["categoryIDs"] != nil {
var cats []int
if err = utils.UnmarshalUseNumber([]byte(params["categoryIDs"].(string)), &cats); err != nil {
return 0, err
}
if len(cats) > 0 {
sqlCatAndSku += " AND (t3.category_id IN (" + dao.GenQuestionMarks(len(cats)) + ") OR t4.parent_id IN (" + dao.GenQuestionMarks(len(cats)) + "))"
sqlCatAndSkuParams = append(sqlCatAndSkuParams, cats, cats)
}
}
if params["skuIDs"] != nil {
var skus []int
if err = utils.UnmarshalUseNumber([]byte(params["skuIDs"].(string)), &skus); err != nil {
return 0, err
}
if len(skus) > 0 {
sqlCatAndSku += " AND t1.sku_id IN (" + dao.GenQuestionMarks(len(skus)) + ")"
sqlCatAndSkuParams = append(sqlCatAndSkuParams, skus)
}
}
pricePercentage := 100
if params["pricePercentage"] != nil {
pricePercentage = params["pricePercentage"].(int)
}
dao.Begin(db)
defer func() {
dao.Rollback(db)
if r := recover(); r != nil {
panic(r)
}
}()
if copyMode == CopyStoreSkuModeFresh || copyMode == CopyStoreSkuModeUpdate {
sqlDelete := `
UPDATE store_sku_bind t1
JOIN sku t2 ON t1.sku_id = t2.id
JOIN sku_name t3 ON t2.name_id = t3.id
SET t1.deleted_at = ?,
t1.last_operator = ?,
t1.status = ?,
t1.jd_sync_status = ?,
t1.elm_sync_status = ?,
t1.ebai_sync_status = ?
WHERE t1.store_id = ? AND t1.deleted_at = ?
`
sqlDeleteParams := []interface{}{
time.Now(),
userName,
model.StoreSkuBindStatusDeleted,
model.SyncFlagDeletedMask,
model.SyncFlagDeletedMask,
model.SyncFlagDeletedMask,
toStoreID,
utils.DefaultTimeValue,
}
if copyMode == CopyStoreSkuModeUpdate {
sqlDelete += sqlCatAndSku
sqlDeleteParams = append(sqlDeleteParams, sqlCatAndSkuParams)
}
if _, err = dao.ExecuteSQL(db, sqlDelete, sqlDeleteParams); err != nil {
return 0, err
}
}
sql := `
INSERT INTO store_sku_bind(created_at, updated_at, last_operator, deleted_at, store_id, sku_id, sub_store_id, price, unit_price, status, jd_sync_status, elm_sync_status, ebai_sync_status)
SELECT NOW(), NOW(), ?, ?,
?, t1.sku_id, 0, t1.price * ? / 100, t1.unit_price * ? / 100, t1.status, ?, ?, ?
FROM store_sku_bind t1
JOIN sku t2 ON t1.sku_id = t2.id
JOIN sku_name t3 ON t2.name_id = t3.id
JOIN sku_category t4 ON t3.category_id = t4.id
WHERE t1.store_id = ? AND t1.deleted_at = ?
`
sqlParams := []interface{}{
userName,
utils.DefaultTimeValue,
toStoreID,
pricePercentage,
pricePercentage,
model.SyncFlagNewMask,
model.SyncFlagNewMask,
model.SyncFlagNewMask,
fromStoreID,
utils.DefaultTimeValue,
}
sql += sqlCatAndSku
sqlParams = append(sqlParams, sqlCatAndSkuParams)
num, err = dao.ExecuteSQL(db, sql, sqlParams)
if err == nil {
dao.Commit(db)
}
return num, err
}
func setStoreSkuBindStatus(skuBind *model.StoreSkuBind, status int8) {
skuBind.JdSyncStatus |= status
skuBind.ElmSyncStatus |= status
skuBind.EbaiSyncStatus |= status
}