Files
jx-callback/business/jxstore/cms/store_sku.go

1780 lines
62 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"
"fmt"
"math"
"sort"
"strconv"
"sync"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/auth/weixin"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"github.com/astaxie/beego/orm"
)
const (
MaxSkuUnitPrice = 100000
CopyStoreSkuModeFresh = "fresh"
CopyStoreSkuModeUpdate = "update"
// CopyStoreSkuModeAdd = "add"
)
// GetStoreSkus用
type StoreSkuNameExt struct {
StoreID int `orm:"column(store_id)" json:"storeID"`
StoreName string `json:"storeName"`
model.SkuName
UnitPrice int `json:"unitPrice"`
Skus []map[string]interface{} `orm:"-" json:"skus"`
SkusStr string `json:"-"`
PendingOpType int8 `json:"pendingOpType"` // 取值同 StoreOpRequest.Type
PendingUnitPrice int `json:"pendingUnitPrice"` // 这个是待审核的价格申请
}
// 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,omitempty"` // -1不可售0忽略1可售
ElmID int64 `json:"elmID,omitempty"`
EbaiID int64 `json:"ebaiID,omitempty"`
}
// UpdateStoreSku用API调用时
type StoreSkuBindInfo struct {
StoreID int `json:"storeID"`
NameID int `json:"nameID"`
UnitPrice int `json:"unitPrice"` // 对于是份的SKU就是单价每斤价格其它则为总价
IsFocus int `json:"isFocus"` // -1不关注0忽略1关注
IsSale int `json:"isSale"` // -1不可售0忽略1可售
SubStoreID int `json:"subStoreID,omitempty"`
Skus []*StoreSkuBindSkuInfo `json:"skus,omitempty"`
}
type tStoreSkuBindAndSpec struct {
model.StoreSkuBind
Name string
SpecQuality float32
SpecUnit string
SkuNamePrice int
SkuNameUnit string
RealSkuID int `orm:"column(real_sku_id)"`
}
type SkuSaleInfo struct {
StoreID int `orm:"column(store_id)"`
SkuID int `orm:"column(sku_id)"`
Times int // 销售的次数
Count int // 销售的总份数
}
type StoreOpRequestInfo struct {
model.StoreOpRequest
StoreName string `json:"storeName"`
SkuNamePrefix string `json:"skuNamePrefix"`
SkuNameName string `json:"skuNameName"`
UnitPrice int `json:"unitPrice"`
}
const (
maxStoreNameBind = 3000 // 最大门店SkuName bind个数
maxStoreNameBind2 = 10000 // 最大门店乘SkuName个数
)
func GetStoreSkus(ctx *jxcontext.Context, storeID int, isFocus bool, keyword string, isBySku bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *StoreSkuNamesInfo, err error) {
return GetStoresSkus(ctx, []int{storeID}, isFocus, keyword, isBySku, params, offset, pageSize)
}
// 商品不可售,直接排除
// 如果门店商品是可售状态,那么会忽略区域限制。否则有区域限制
func GetStoresSkus(ctx *jxcontext.Context, storeIDs []int, isFocus bool, keyword string, isBySku bool, 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 = ?/* AND t2.status = ?*/
JOIN store t3 ON t3.id IN (` + dao.GenQuestionMarks(len(storeIDs)) + `)
LEFT JOIN store_sku_bind t4 ON t4.sku_id = t2.id AND t4.deleted_at = ? AND t4.store_id = 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 = ? AND (t1.is_global = 1 OR t5.id IS NOT NULL OR 1 = ?)/* AND t1.status = ?*/
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
// model.SkuStatusNormal,
storeIDs,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
utils.Bool2Int(isFocus),
// model.SkuStatusNormal,
}
if isFocus {
sql += " AND t4.sku_id IS NOT NULL AND ((t2.status = ? AND t1.status = ?) OR t4.status = ?)"
sqlParams = append(sqlParams, model.SkuStatusNormal, model.SkuStatusNormal, model.SkuStatusNormal)
} else {
sql += " AND t4.sku_id IS NULL AND t2.status = ? AND t1.status = ?"
sqlParams = append(sqlParams, model.SkuStatusNormal, model.SkuStatusNormal)
}
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += " AND (t1.name LIKE ? OR t1.prefix LIKE ? OR t1.upc LIKE ? OR t2.comment LIKE ?"
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike)
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
sql += " OR t1.id = ? OR t2.id = ? OR t2.jd_id = ? OR t4.ebai_id = ? OR t4.mtwm_id = ?"
sqlParams = append(sqlParams, keywordInt64, keywordInt64, keywordInt64, keywordInt64, keywordInt64)
}
sql += ")"
}
if params["nameID"] != nil {
sql += " AND t1.id = ?"
sqlParams = append(sqlParams, params["nameID"].(int))
}
if params["nameIDs"] != nil {
var nameIDs []int
if err = utils.UnmarshalUseNumber([]byte(params["nameIDs"].(string)), &nameIDs); err != nil {
return nil, err
}
if len(nameIDs) > 0 {
sql += " AND t1.id IN (" + dao.GenQuestionMarks(len(nameIDs)) + ")"
sqlParams = append(sqlParams, nameIDs)
}
}
if params["categoryID"] != nil {
cat := &model.SkuCategory{}
cat.ID = params["categoryID"].(int)
if err = dao.GetEntity(db, cat); err != nil {
return nil, err
}
sql += " AND (t1.category_id = ?"
sqlParams = append(sqlParams, cat.ID)
if cat.Level == 1 {
sql += " OR t1.category_id IN (SELECT id FROM sku_category WHERE parent_id = ?)"
sqlParams = append(sqlParams, cat.ID)
}
sql += ")"
}
if params["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))
}
var skuIDs []int
if params["skuIDs"] != nil {
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)
}
} else if params["skuID"] != nil {
skuID, ok := params["skuID"].(int)
if ok {
skuIDs = append(skuIDs, skuID)
sql += " AND t2.id = ?"
sqlParams = append(sqlParams, skuID)
}
}
if isFocus {
if 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)
}
if params["jdSyncStatus"] != nil || params["ebaiSyncStatus"] != nil || params["mtwmSyncStatus"] != nil {
realVendorMap, err2 := getValidStoreVendorMap(db, storeIDs)
if err = err2; err != nil {
return nil, err
}
sql += " AND ( 1 = 0"
if params["jdSyncStatus"] != nil && realVendorMap[model.VendorIDJD] == 1 {
sql += " OR (t4.jd_sync_status & ? <> 0 AND t4.jd_sync_status & ? = 0 AND t2.jd_id <> 0 AND t1.status = ? AND t2.status = ?)"
sqlParams = append(sqlParams, params["jdSyncStatus"], model.SyncFlagDeletedMask|model.SyncFlagNewMask, model.SkuStatusNormal, model.SkuStatusNormal)
}
if params["ebaiSyncStatus"] != nil && realVendorMap[model.VendorIDEBAI] == 1 {
sql += " OR (t4.ebai_sync_status & ? <> 0 AND t4.ebai_sync_status & ? = 0)"
sqlParams = append(sqlParams, params["ebaiSyncStatus"], model.SyncFlagDeletedMask|model.SyncFlagNewMask)
}
if params["mtwmSyncStatus"] != nil && realVendorMap[model.VendorIDMTWM] == 1 {
sql += " OR (t4.mtwm_sync_status & ? <> 0 AND t4.mtwm_sync_status & ? = 0)"
sqlParams = append(sqlParams, params["mtwmSyncStatus"], model.SyncFlagDeletedMask|model.SyncFlagNewMask)
}
sql += ")"
}
}
sql += `
GROUP BY
t1.id,
t1.created_at,
t1.updated_at,
t1.last_operator,
t1.deleted_at,
t1.prefix,
t1.name,
t1.brand_id,
t1.category_id,
t1.is_global,
t1.unit,
t1.price,
t1.img,
t1.elm_img_hash_code,
t3.id,
t3.name`
if isBySku {
sql += `,
t2.id`
}
sqlData := `
SELECT
SQL_CALC_FOUND_ROWS
t1.id,
t1.created_at,
t1.updated_at,
t1.last_operator,
t1.deleted_at,
t1.prefix,
t1.name,
t1.brand_id,
t1.category_id,
t1.is_global,
t1.unit,
t1.price,
t1.img,
t1.elm_img_hash_code,
t3.id store_id,
t3.name store_name,
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"id":', t2.id, ',"comment":"', t2.comment, '","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,
',"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),
',"jdID":', t2.jd_id, ',"jdSyncStatus":', IF(t4.jd_sync_status IS NULL, 0, t4.jd_sync_status),
',"ebaiID":', IF(t4.ebai_id IS NULL, 0, t4.ebai_id), ',"ebaiSyncStatus":', IF(t4.ebai_sync_status IS NULL, 0, t4.ebai_sync_status),
',"mtwmID":', IF(t4.mtwm_id IS NULL, 0, t4.mtwm_id), ',"mtwmSyncStatus":', IF(t4.mtwm_sync_status IS NULL, 0, t4.mtwm_sync_status),
',"wscID":', IF(t4.wsc_id IS NULL, 0, t4.wsc_id), ',"wscSyncStatus":', IF(t4.wsc_sync_status IS NULL, 0, t4.wsc_sync_status),
"}")), "]") skus_str
` + sql + `
ORDER BY t1.id DESC
LIMIT ? OFFSET ?`
pageSize = jxutils.FormalizePageSize(pageSize)
sqlOffset := offset
sqlPageSize := pageSize
isSaleInfo := params["stFromTime"] != nil
if isSaleInfo {
sqlOffset = 0
sqlPageSize = jxutils.FormalizePageSize(-1)
}
sqlParams = append(sqlParams, sqlPageSize, sqlOffset)
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 {
skuNamesInfo.TotalCount = dao.GetLastTotalRowCount(db)
// 活动商品信息
jxSkuPriceMap, err2 := dao.GetPromotionSkuPriceMap(db, model.VendorIDJX, storeIDs, skuIDs, time.Now(), time.Now())
if err = err2; err != nil {
dao.Rollback(db)
globals.SugarLogger.Errorf("GetStoresSkus can not get sku promotion info for error:%v", err)
return nil, err
}
jdSkuPriceMap, err2 := dao.GetPromotionSkuPriceMap(db, model.VendorIDJD, storeIDs, skuIDs, time.Now(), time.Now())
if err = err2; err != nil {
dao.Rollback(db)
globals.SugarLogger.Errorf("GetStoresSkus can not get sku promotion info for error:%v", err)
return nil, err
}
for _, skuName := range skuNamesInfo.SkuNames {
if skuName.SkusStr != "" {
if err = utils.UnmarshalUseNumber([]byte(skuName.SkusStr), &skuName.Skus); err != nil {
dao.Rollback(db)
return nil, err
}
if len(skuName.Skus) > 0 {
skuName.UnitPrice = int(utils.MustInterface2Int64(skuName.Skus[0]["unitPrice"]))
for _, v := range skuName.Skus {
index := dao.GenSkuPriceMapKey(skuName.StoreID, int(utils.MustInterface2Int64(v["id"])))
if jdSkuPriceMap[index] != nil {
v["actPrice"] = jdSkuPriceMap[index].Price
} else {
v["actPrice"] = 0
}
if jxSkuPriceMap[index] != nil {
v["earningPrice"] = jxSkuPriceMap[index].EarningPrice
} else {
v["earningPrice"] = 0
}
delete(v, "unitPrice")
}
} else {
skuName.UnitPrice = skuName.Price
}
}
}
if isSaleInfo {
var (
saleInfoList []*SkuSaleInfo
skuIDs []int
timeList []time.Time
fromCount, toCount int
)
saleInfoMap := make(map[int64]*SkuSaleInfo)
for _, skuName := range skuNamesInfo.SkuNames {
for _, sku := range skuName.Skus {
skuIDs = append(skuIDs, int(utils.MustInterface2Int64(sku["id"])))
}
}
toTimeStr := ""
if params["stToTime"] != nil {
toTimeStr = params["stToTime"].(string)
}
if timeList, err = jxutils.BatchStr2Time(params["stFromTime"].(string), toTimeStr); err != nil {
dao.Rollback(db)
return nil, err
}
if params["stFromCount"] != nil {
fromCount = params["stFromCount"].(int)
}
toCount = math.MaxInt32
if params["stToCount"] != nil {
toCount = params["stToCount"].(int)
}
// 不能用SQL筛除否则不能区分是没有销量还是不在条件中
if saleInfoList, err = GetStoresSkusSaleInfo(ctx, storeIDs, skuIDs, timeList[0], timeList[1], 0, math.MaxInt32); err != nil {
dao.Rollback(db)
return nil, err
}
for _, saleInfo := range saleInfoList {
saleInfoMap[int64(saleInfo.StoreID)*100000+int64(saleInfo.SkuID)] = saleInfo
}
var newSkuNames []*StoreSkuNameExt
for _, skuName := range skuNamesInfo.SkuNames {
var newSkus []map[string]interface{}
storeID2 := int64(skuName.StoreID) * 100000
for _, sku := range skuName.Skus {
saleInfo := saleInfoMap[storeID2+utils.MustInterface2Int64(sku["id"])]
if saleInfo == nil && fromCount == 0 {
saleInfo = &SkuSaleInfo{}
}
if saleInfo != nil && saleInfo.Count >= fromCount && saleInfo.Count <= toCount {
sku["times"] = saleInfo.Times
sku["count"] = saleInfo.Count
newSkus = append(newSkus, sku)
}
}
if len(newSkus) > 0 {
skuName.Skus = newSkus
newSkuNames = append(newSkuNames, skuName)
}
}
skuNamesInfo.TotalCount = len(newSkuNames)
skuNamesInfo.SkuNames = nil
if offset < skuNamesInfo.TotalCount {
endIndex := offset + pageSize
if endIndex > skuNamesInfo.TotalCount {
endIndex = skuNamesInfo.TotalCount
}
skuNamesInfo.SkuNames = newSkuNames[offset:endIndex]
}
}
if globals.EnablePendingChange {
if isGetOpRequest, ok := params["isGetOpRequest"].(bool); ok && isGetOpRequest {
nameIDs := make([]int, len(skuNamesInfo.SkuNames))
for k, skuName := range skuNamesInfo.SkuNames {
nameIDs[k] = skuName.ID
}
pagedInfo, err2 := GetStoreOpRequests(ctx, utils.DefaultTimeValue, utils.DefaultTimeValue, "", storeIDs, nameIDs, nil, []int{model.RequestStatusNew}, 0, -1)
if err = err2; err != nil {
return nil, err
}
requestList := pagedInfo.Data.([]*StoreOpRequestInfo)
requestMap := make(map[int]*StoreOpRequestInfo)
for _, requestOp := range requestList {
requestMap[requestOp.ItemID] = requestOp
}
for _, skuName := range skuNamesInfo.SkuNames {
if requestOp := requestMap[skuName.ID]; requestOp != nil {
skuName.PendingUnitPrice = requestOp.IntParam1
skuName.PendingOpType = requestOp.Type
}
}
}
}
}
dao.Commit(db)
return skuNamesInfo, err
}
func getValidStoreVendorMap(db *dao.DaoDB, storeIDs []int) (realVendorMap map[int]int, err error) {
storeMapList, err := dao.GetStoresMapList(db, nil, storeIDs, model.StoreStatusAll)
if err != nil {
return nil, err
}
realVendorMap = make(map[int]int)
for _, v := range storeMapList {
if v.IsSync != 0 {
realVendorMap[v.VendorID] = 1
}
}
return realVendorMap, nil
}
func GetStoreAbnormalSkuCount(ctx *jxcontext.Context, storeID, syncStatus int, isBySku bool, params map[string]interface{}) (count int, err error) {
db := dao.GetDB()
realVendorMap, err2 := getValidStoreVendorMap(db, []int{storeID})
if err = err2; err != nil {
return 0, err
}
sql := `
SELECT COUNT(*) ct`
if !isBySku {
sql += `
FROM (
SELECT DISTINCT t3.id`
}
sql += `
FROM store_sku_bind t1
JOIN sku t2 ON t2.id = t1.sku_id AND t2.deleted_at = ?
JOIN sku_name t3 ON t3.id = t2.name_id AND t3.deleted_at = ?
WHERE t1.deleted_at = ? AND t1.store_id = ? AND
((t2.status = ? AND t3.status = ?) OR t1.status = ?) AND
(1 = 0`
sqlParams := []interface{}{
utils.DefaultTimeValue,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
storeID,
model.SkuStatusNormal,
model.SkuStatusNormal,
model.SkuStatusNormal,
}
for _, vendorID := range []int{model.VendorIDJD, model.VendorIDEBAI, model.VendorIDMTWM} {
if realVendorMap[vendorID] != 0 {
prefix := dao.ConvertDBFieldPrefix(model.VendorNames[vendorID])
sql += fmt.Sprintf(" OR (t1.%s_sync_status & ? <> 0 AND t1.%s_sync_status & ? = 0", prefix, prefix)
sqlParams = append(sqlParams, syncStatus, model.SyncFlagDeletedMask|model.SyncFlagNewMask)
if model.MultiStoresVendorMap[vendorID] == 1 {
sql += fmt.Sprintf(" AND t2.%s_id <> 0 AND t2.status = ? AND t3.status = ?", prefix)
sqlParams = append(sqlParams, model.SkuStatusNormal, model.SkuStatusNormal)
}
sql += ")"
}
}
sql += ")"
if params["fromStatus"] != nil {
fromStatus := params["fromStatus"].(int)
toStatus := fromStatus
if params["toStatus"] != nil {
toStatus = params["toStatus"].(int)
}
sql += " AND t1.status >= ? AND t1.status <= ?"
sqlParams = append(sqlParams, fromStatus, toStatus)
}
if !isBySku {
sql += `
) t1`
}
err = dao.GetRow(db, &count, sql, sqlParams...)
return count, err
}
func GetStoresSkusSaleInfo(ctx *jxcontext.Context, storeIDs []int, skuIDs []int, fromTime, toTime time.Time, fromCount, toCount int) (saleInfoList []*SkuSaleInfo, err error) {
globals.SugarLogger.Debugf("GetStoresSkusSaleInfo storeIDs:%v, fromTime:%v, toTime:%v, fromCount:%d, toCount:%d", storeIDs, fromTime, toTime, fromCount, toCount)
db := dao.GetDB()
sql := `
SELECT IF(t2.jx_store_id <> 0, jx_store_id, store_id) store_id, t1.sku_id, COUNT(*) times, SUM(count) count
FROM order_sku t1
JOIN goods_order t2 ON t1.vendor_order_id = t2.vendor_order_id AND t1.vendor_id = t2.vendor_id AND t2.status = ?
WHERE t1.order_created_at >= ? AND t1.order_created_at <= ?
AND IF(t2.jx_store_id <> 0, jx_store_id, store_id) IN (` + dao.GenQuestionMarks(len(storeIDs)) + `)
`
if utils.IsTimeZero(toTime) {
toTime = time.Now()
}
sqlParams := []interface{}{
model.OrderStatusFinished,
fromTime,
toTime,
storeIDs,
}
if len(skuIDs) > 0 {
sql += `
AND IF(t1.jx_sku_id <> 0, t1.jx_sku_id, t1.sku_id) IN (` + dao.GenQuestionMarks(len(skuIDs)) + `)`
sqlParams = append(sqlParams, skuIDs)
}
sql += `
GROUP BY 1,2
HAVING count >= ? AND count <= ?
`
sqlParams = append(sqlParams, fromCount, toCount)
// fmt.Println(sql)
// fmt.Println(utils.Format4Output(sqlParams, false))
if err = dao.GetRows(db, &saleInfoList, sql, sqlParams...); err == nil {
// globals.SugarLogger.Debug(utils.Format4Output(saleInfoList, false))
return saleInfoList, nil
}
return nil, err
}
func UpdateStoreSku(ctx *jxcontext.Context, storeID int, skuBindInfo *StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
return UpdateStoreSkus(ctx, storeID, []*StoreSkuBindInfo{skuBindInfo}, isAsync, isContinueWhenError)
}
func UpdateStoreSkus(ctx *jxcontext.Context, storeID int, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
return UpdateStoresSkus(ctx, []int{storeID}, skuBindInfos, isAsync, isContinueWhenError)
}
func UpdateStoresSkus(ctx *jxcontext.Context, storeIDs []int, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
var num int64
db := dao.GetDB()
skuIDs, err := updateStoresSkusWithoutSync(ctx, db, storeIDs, skuBindInfos)
if err != nil {
return "", err
}
num = int64(len(skuIDs))
if num > 0 {
hint, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
}
if num == 0 || !isAsync || hint == "" {
hint = utils.Int64ToStr(num)
}
return hint, err
}
func UpdateStoresSkusByBind(ctx *jxcontext.Context, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
if len(skuBindInfos) > maxStoreNameBind {
return "", fmt.Errorf("门店商品信息大于%d", maxStoreNameBind)
}
skuBindInfosMap := make(map[int][]*StoreSkuBindInfo)
storeIDMap := make(map[int]int)
for _, v := range skuBindInfos {
if v.StoreID > 9 {
skuBindInfosMap[v.StoreID] = append(skuBindInfosMap[v.StoreID], v)
storeIDMap[v.StoreID] = 1
}
}
storeIDs := jxutils.IntMap2List(storeIDMap)
sort.Ints(storeIDs)
var num int64
skuIDMap := make(map[int]int)
db := dao.GetDB()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
for _, storeID := range storeIDs {
skuIDs, err2 := updateStoresSkusWithoutSync(ctx, db, []int{storeID}, skuBindInfosMap[storeID])
if err = err2; err != nil {
dao.Rollback(db)
return "", err
}
for _, v := range skuIDs {
skuIDMap[v] = 1
}
num += int64(len(skuIDs))
}
dao.Commit(db)
if num > 0 {
skuIDs := jxutils.IntMap2List(skuIDMap)
hint, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
}
if num == 0 || !isAsync || hint == "" {
hint = utils.Int64ToStr(num)
}
return hint, err
}
func checkStoresSkusSaleCity(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs []int, skuBindInfos []*StoreSkuBindInfo) (err error) {
sql := `
SELECT t1.id store_id, t2.id name_id, t2.name
FROM store t1
JOIN sku_name t2 ON t2.is_global = 0 AND t2.deleted_at = ?
LEFT JOIN sku_name_place_bind t3 ON t2.id = t3.name_id AND t1.city_code = t3.place_code
WHERE t3.id IS NULL
`
sql += " AND t1.id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
nameIDs := make([]int, 0)
for _, v := range skuBindInfos {
if v.IsFocus == 1 {
nameIDs = append(nameIDs, v.NameID)
} else {
for _, v2 := range v.Skus {
if v2.IsSale == 1 {
nameIDs = append(nameIDs, v.NameID)
break
}
}
}
}
if len(nameIDs) == 0 {
return nil
}
sql += " AND t2.id IN (" + dao.GenQuestionMarks(len(nameIDs)) + ")"
var invalidList []*struct {
StoreID int `orm:"column(store_id)"`
NameID int `orm:"column(name_id)"`
Name string
}
if err = dao.GetRows(db, &invalidList, sql, utils.DefaultTimeValue, storeIDs, nameIDs); err == nil {
if len(invalidList) > 0 {
errMsg := ""
for _, v := range invalidList {
errMsg += fmt.Sprintf("门店:%dName:%d(%s)销售区域错误!\n", v.StoreID, v.NameID, v.Name)
}
err = errors.New(errMsg)
}
}
return err
}
func uniqueStoreIDs(storeIDs []int) []int {
storeIDMap := make(map[int]int)
for _, v := range storeIDs {
storeIDMap[v] = 1
}
return jxutils.IntMap2List(storeIDMap)
}
func uniqueStoreNameBind(skuBindInfos []*StoreSkuBindInfo) (outSkuBindInfos []*StoreSkuBindInfo) {
nameIDMap := make(map[int]int)
for _, v := range skuBindInfos {
if nameIDMap[v.NameID] != 1 {
outSkuBindInfos = append(outSkuBindInfos, v)
nameIDMap[v.NameID] = 1
}
}
return outSkuBindInfos
}
func updateStoresSkusWithoutSync(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs []int, skuBindInfos []*StoreSkuBindInfo) (needSyncSkus []int, err error) {
if len(storeIDs)*len(skuBindInfos) > maxStoreNameBind2 {
return nil, fmt.Errorf("门店商品信息大于%d", maxStoreNameBind2)
}
storeIDs = uniqueStoreIDs(storeIDs)
skuBindInfos = uniqueStoreNameBind(skuBindInfos)
sort.Ints(storeIDs)
globals.SugarLogger.Debugf("updateStoresSkusWithoutSync, storeIDs:%v, skuBindInfos:%s", storeIDs, utils.Format4Output(skuBindInfos, false))
if db == nil {
db = dao.GetDB()
}
// if err = checkStoresSkusSaleCity(ctx, db, storeIDs, skuBindInfos); err != nil {
// return nil, err
// }
if storeIDs, skuBindInfos, err = filterStorePriceChange(ctx, storeIDs, skuBindInfos); err != nil {
return nil, err
}
globals.SugarLogger.Debugf("updateStoresSkusWithoutSync2, storeIDs:%v, skuBindInfos:%s", storeIDs, utils.Format4Output(skuBindInfos, false))
userName := ctx.GetUserName()
needSyncIDMap := make(map[int]int)
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
for _, storeID := range storeIDs {
for _, skuBindInfo := range skuBindInfos {
// 关注且没有给价时需要尝试从store_sku_bind中得到已有的单价
needGetExistingUnitPrice := skuBindInfo.UnitPrice == 0 && skuBindInfo.IsFocus == 1
inSkuBinds := skuBindInfo.Skus
var allBinds []*tStoreSkuBindAndSpec
sql := `
SELECT
t2.*,
t1.id real_sku_id, t1.spec_quality, t1.spec_unit,`
if needGetExistingUnitPrice {
sql += " IF(t5.unit_price > 0, t5.unit_price, t3.price) sku_name_price,"
}
sql += `
t3.unit sku_name_unit, t3.name
FROM sku t1
JOIN store ts ON ts.id = ? AND ts.deleted_at = ?
LEFT JOIN store_sku_bind t2 ON t2.sku_id = t1.id AND t2.store_id = ts.id AND t2.deleted_at = ?
JOIN sku_name t3 ON t1.name_id = t3.id AND t3.deleted_at = ?`
sqlParams := []interface{}{
storeID,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
}
if needGetExistingUnitPrice {
sql += `
LEFT JOIN (
SELECT t7.store_id, t8.name_id, CAST(AVG(t7.unit_price) AS SIGNED) unit_price
FROM store_sku_bind t7
JOIN sku t8 ON t8.id = t7.sku_id AND t8.name_id = ?
WHERE t7.deleted_at = ? AND t7.store_id = ?
GROUP BY 1,2
) t5 ON t5.store_id = ts.id AND t5.name_id = t1.name_id`
sqlParams = append(sqlParams, skuBindInfo.NameID, utils.DefaultTimeValue, storeID)
}
sql += `
WHERE t1.name_id = ? AND t1.deleted_at = ?
FOR UPDATE`
sqlParams = append(sqlParams, skuBindInfo.NameID, utils.DefaultTimeValue)
// globals.SugarLogger.Debug(sql)
if err = dao.GetRows(db, &allBinds, sql, sqlParams...); err == nil {
if len(allBinds) > 0 {
// globals.SugarLogger.Debug(utils.Format4Output(allBinds, false))
inSkuBinsMap := make(map[int]*StoreSkuBindSkuInfo, len(inSkuBinds))
for _, v := range inSkuBinds {
inSkuBinsMap[v.SkuID] = v
}
unitPrice := 0
if skuBindInfo.UnitPrice != 0 {
if skuBindInfo.UnitPrice > MaxSkuUnitPrice {
dao.Rollback(db)
return nil, fmt.Errorf("商品:%s价格:%s太夸张", allBinds[0].Name, jxutils.IntPrice2StandardCurrencyString(int64(skuBindInfo.UnitPrice)))
}
unitPrice = skuBindInfo.UnitPrice
} else {
unitPrice = allBinds[0].UnitPrice
if unitPrice == 0 {
unitPrice = allBinds[0].SkuNamePrice
}
}
for _, v := range allBinds {
var num int64
inSkuBind := inSkuBinsMap[v.RealSkuID]
// globals.SugarLogger.Debug(utils.Format4Output(inSkuBind, false))
var skuBind *model.StoreSkuBind
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 tmpStatus := getSkuSaleStatus(inSkuBind, skuBindInfo); tmpStatus != model.StoreSkuBindStatusNA {
skuBind.Status = tmpStatus
}
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,
model.FieldMtwmSyncStatus: model.SyncFlagDeletedMask,
model.FieldWscSyncStatus: model.SyncFlagDeletedMask,
}, userName, nil); err != nil {
dao.Rollback(db)
return nil, err
}
} else {
// 用了SELECT FOR UPDATE后只更新修改字段是没有必要的暂时保留
updateFieldMap := make(map[string]int)
if skuBindInfo.IsFocus == 1 { // 关注之后再关注不操作
// skuBind.Status = model.StoreSkuBindStatusDontSale // 缺省不可售?
// skuBind.DeletedAt = utils.DefaultTimeValue
// skuBind.UnitPrice = unitPrice
// skuBind.Price = jxutils.CaculateSkuPrice(unitPrice, v.SpecQuality, v.SpecUnit, v.SkuNameUnit)
// setStoreSkuBindStatus(skuBind, model.SyncFlagPriceMask|model.SyncFlagSaleMask)
// updateFieldMap[model.FieldStatus] = 1
// updateFieldMap[model.FieldDeletedAt] = 1
// updateFieldMap["UnitPrice"] = 1
// updateFieldMap["Price"] = 1
}
if tmpStatus := getSkuSaleStatus(inSkuBind, skuBindInfo); tmpStatus != model.StoreSkuBindStatusNA {
skuBind.Status = tmpStatus
setStoreSkuBindStatus(skuBind, model.SyncFlagSaleMask)
updateFieldMap[model.FieldStatus] = 1
}
if skuBindInfo.UnitPrice != 0 { // 这里是否需要加此条件限制
skuBind.UnitPrice = unitPrice
skuBind.Price = jxutils.CaculateSkuPrice(unitPrice, v.SpecQuality, v.SpecUnit, v.SkuNameUnit)
setStoreSkuBindStatus(skuBind, model.SyncFlagPriceMask)
updateFieldMap["UnitPrice"] = 1
updateFieldMap["Price"] = 1
}
// todo 这里应该是不需处理这个信息的吧?
// if inSkuBind != nil && inSkuBind.EbaiID != 0 {
// skuBind.EbaiID = inSkuBind.EbaiID
// updateFieldMap["EbaiID"] = 1
// }
// if inSkuBind != nil && inSkuBind.ElmID != 0 {
// skuBind.ElmID = inSkuBind.ElmID
// updateFieldMap["ElmID"] = 1
// }
if len(updateFieldMap) > 0 {
updateFieldMap[model.FieldJdSyncStatus] = 1
updateFieldMap[model.FieldElmSyncStatus] = 1
updateFieldMap[model.FieldEbaiSyncStatus] = 1
updateFieldMap[model.FieldMtwmSyncStatus] = 1
updateFieldMap[model.FieldWscSyncStatus] = 1
updateFieldMap[model.FieldUpdatedAt] = 1
updateFieldMap[model.FieldLastOperator] = 1
// setStoreSkuBindStatus(skuBind, model.SyncFlagModifiedMask)
dao.WrapUpdateULEntity(skuBind, userName)
if num, err = dao.UpdateEntity(db, skuBind /*, utils.Map2KeySlice(updateFieldMap)...*/); err != nil {
dao.Rollback(db)
return nil, err
}
}
}
}
if skuBind != nil && num == 1 {
needSyncIDMap[skuBind.SkuID] = 1
}
}
}
} else {
dao.Rollback(db)
return nil, err
}
}
}
dao.Commit(db)
skuIDs := jxutils.IntMap2List(needSyncIDMap)
return skuIDs, err
}
func getSkuSaleStatus(inSkuBind *StoreSkuBindSkuInfo, skuBindInfo *StoreSkuBindInfo) int {
tempSale := 0
if inSkuBind != nil {
tempSale = inSkuBind.IsSale
} else {
tempSale = skuBindInfo.IsSale
}
if tempSale == -1 {
return model.StoreSkuBindStatusDontSale
} else if tempSale == 1 {
return model.StoreSkuBindStatusNormal
}
return model.StoreSkuBindStatusNA
}
// todo 应该用updateStoresSkusWithoutSync实现
func updateStoreSkusSaleWithoutSync(ctx *jxcontext.Context, storeID int, skuBindSkuInfos []*StoreSkuBindSkuInfo, userName string) (needSyncSkus []int, err error) {
var num int64
db := dao.GetDB()
needSyncIDMap := make(map[int]int)
skuIDMap := make(map[int]int)
skuBindSkuInfosMap := make(map[int]*StoreSkuBindSkuInfo)
for _, v := range skuBindSkuInfos {
skuIDMap[v.SkuID] = 1
skuBindSkuInfosMap[v.SkuID] = v
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
storeSkuList, err := dao.GetStoresSkusInfo(db, []int{storeID}, jxutils.IntMap2List(skuIDMap))
if err != nil {
dao.Rollback(db)
return nil, err
}
for _, skuBind := range storeSkuList {
if v := skuBindSkuInfosMap[skuBind.SkuID]; v != nil && v.IsSale != 0 {
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,
model.FieldJdSyncStatus: skuBind.JdSyncStatus | model.SyncFlagSaleMask,
model.FieldEbaiSyncStatus: skuBind.EbaiSyncStatus | model.SyncFlagSaleMask,
model.FieldMtwmSyncStatus: skuBind.MtwmSyncStatus | model.SyncFlagSaleMask,
model.FieldElmSyncStatus: skuBind.ElmSyncStatus | model.SyncFlagSaleMask,
model.FieldWscSyncStatus: skuBind.WscSyncStatus | model.SyncFlagSaleMask,
}, userName, nil); 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 uniqueStoreSkuBind(skuBindSkuInfos []*StoreSkuBindSkuInfo) (outSkuBindSkuInfos []*StoreSkuBindSkuInfo) {
skuIDMap := make(map[int]int)
for _, v := range skuBindSkuInfos {
if skuIDMap[v.SkuID] != 1 {
outSkuBindSkuInfos = append(outSkuBindSkuInfos, v)
skuIDMap[v.SkuID] = 1
}
}
return outSkuBindSkuInfos
}
func UpdateStoresSkusSale(ctx *jxcontext.Context, storeIDs []int, skuBindSkuInfos []*StoreSkuBindSkuInfo, userName string, isAsync, isContinueWhenError bool) (hint string, err error) {
storeIDs = uniqueStoreIDs(storeIDs)
skuBindSkuInfos = uniqueStoreSkuBind(skuBindSkuInfos)
var num int64
for _, storeID := range storeIDs {
skuIDs, err2 := updateStoreSkusSaleWithoutSync(ctx, storeID, skuBindSkuInfos, userName)
if err = err2; err != nil {
return "", err
}
num += int64(len(skuIDs))
}
if num > 0 {
skuIDs := make([]int, 0)
for _, v := range skuBindSkuInfos {
skuIDs = append(skuIDs, v.SkuID)
}
db := dao.GetDB()
hint, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
}
if num == 0 || !isAsync || hint == "" {
hint = utils.Int64ToStr(num)
}
return hint, err
}
func CopyStoreSkus(ctx *jxcontext.Context, 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()
if err = checkStoreExisting(db, fromStoreID); err != nil {
return 0, err
}
if err = checkStoreExisting(db, toStoreID); err != nil {
return 0, err
}
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)
}
now := time.Now()
if fromStoreID == toStoreID {
sql := `
UPDATE store_sku_bind t1
JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ?
JOIN sku_name t3 ON t2.name_id = t3.id AND t2.deleted_at = ?
LEFT JOIN sku_category t4 ON t3.category_id = t4.id AND t2.deleted_at = ?
SET t1.last_operator = ?,
t1.updated_at = ?,
t1.price = t1.price * ? / 100,
t1.unit_price = t1.unit_price * ? / 100,
t1.jd_sync_status = t1.jd_sync_status | ?,
t1.elm_sync_status = t1.elm_sync_status | ?,
t1.wsc_sync_status = t1.wsc_sync_status | ?,
t1.mtwm_sync_status = t1.mtwm_sync_status | ?,
t1.ebai_sync_status = t1.ebai_sync_status | ?
WHERE t1.store_id = ? AND t1.deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
userName,
now,
pricePercentage,
pricePercentage,
model.SyncFlagPriceMask,
model.SyncFlagPriceMask,
model.SyncFlagPriceMask,
model.SyncFlagPriceMask,
model.SyncFlagPriceMask,
toStoreID,
utils.DefaultTimeValue,
}
sql += sqlCatAndSku
sqlParams = append(sqlParams, sqlCatAndSkuParams)
num, err = dao.ExecuteSQL(db, sql, sqlParams)
return num, err
}
dao.Begin(db)
defer func() {
dao.Rollback(db)
if r := recover(); r != nil {
panic(r)
}
}()
if copyMode == CopyStoreSkuModeFresh || copyMode == CopyStoreSkuModeUpdate {
// 将toStore中存在但fromStore中不存在的置删除标志
sqlDelete := `
UPDATE store_sku_bind t1
LEFT JOIN store_sku_bind t0 ON t0.store_id = ? AND t0.sku_id = t1.sku_id AND t0.deleted_at = ?
JOIN sku t2 ON t1.sku_id = t2.id/* AND t2.deleted_at = ?*/
JOIN sku_name t3 ON t2.name_id = t3.id/* AND t2.deleted_at = ?*/
LEFT JOIN sku_category t4 ON t3.category_id = t4.id AND t2.deleted_at = ?
SET t1.deleted_at = ?,
t1.updated_at = ?,
t1.last_operator = ?,
t1.status = ?,
t1.jd_sync_status = IF((t1.jd_sync_status & ?) <> 0, 0, ?),
t1.elm_sync_status = IF((t1.elm_sync_status & ?) <> 0, 0, ?),
t1.wsc_sync_status = IF((t1.wsc_sync_status & ?) <> 0, 0, ?),
t1.mtwm_sync_status = IF((t1.mtwm_sync_status & ?) <> 0, 0, ?),
t1.ebai_sync_status = IF((t1.ebai_sync_status & ?) <> 0, 0, ?)
WHERE t1.store_id = ? AND t1.deleted_at = ? AND t0.id IS NULL
`
sqlDeleteParams := []interface{}{
fromStoreID,
utils.DefaultTimeValue,
// utils.DefaultTimeValue,
// utils.DefaultTimeValue,
utils.DefaultTimeValue,
now,
now,
userName,
model.StoreSkuBindStatusDeleted,
model.SyncFlagNewMask,
model.SyncFlagDeletedMask,
model.SyncFlagNewMask,
model.SyncFlagDeletedMask,
model.SyncFlagNewMask,
model.SyncFlagDeletedMask,
model.SyncFlagNewMask,
model.SyncFlagDeletedMask,
model.SyncFlagNewMask,
model.SyncFlagDeletedMask,
toStoreID,
utils.DefaultTimeValue,
}
if copyMode == CopyStoreSkuModeUpdate {
sqlDelete += sqlCatAndSku
sqlDeleteParams = append(sqlDeleteParams, sqlCatAndSkuParams)
}
// globals.SugarLogger.Debug(sqlDelete)
if num, err = dao.ExecuteSQL(db, sqlDelete, sqlDeleteParams); err != nil {
return 0, err
}
globals.SugarLogger.Debugf("CopyStoreSkus trackInfo:%s num1:%d", ctx.GetTrackInfo(), num)
}
// 处理toStore中与fromStore中都存在的
sql := `
UPDATE store_sku_bind t1
LEFT JOIN store_sku_bind t0 ON t0.store_id = ? AND t0.sku_id = t1.sku_id AND t0.deleted_at = ?
JOIN sku t2 ON t1.sku_id = t2.id/* AND t2.deleted_at = ?*/
JOIN sku_name t3 ON t2.name_id = t3.id/* AND t3.deleted_at = ?*/
LEFT JOIN sku_category t4 ON t3.category_id = t4.id AND t4.deleted_at = ?
SET t1.last_operator = ?,
t1.updated_at = ?,
t1.sub_store_id = 0,
t1.price = IF(t0.price * ? / 100 > 0, t0.price * ? / 100, 1),
t1.unit_price = IF(t0.unit_price * ? / 100 > 0, t0.unit_price * ? / 100, 1),
t1.status = t0.status,
t1.jd_sync_status = t1.jd_sync_status | ?,
t1.elm_sync_status = t1.elm_sync_status | ?,
t1.wsc_sync_status = t1.wsc_sync_status | ?,
t1.mtwm_sync_status = t1.mtwm_sync_status | ?,
t1.ebai_sync_status = t1.ebai_sync_status | ?
WHERE t1.store_id = ? AND t1.deleted_at = ? AND t0.id IS NOT NULL
`
sqlParams := []interface{}{
fromStoreID,
utils.DefaultTimeValue,
// utils.DefaultTimeValue,
// utils.DefaultTimeValue,
utils.DefaultTimeValue,
userName,
now,
pricePercentage,
pricePercentage,
pricePercentage,
pricePercentage,
model.SyncFlagStoreSkuOnlyMask,
model.SyncFlagStoreSkuOnlyMask,
model.SyncFlagStoreSkuOnlyMask,
model.SyncFlagStoreSkuOnlyMask,
model.SyncFlagStoreSkuOnlyMask,
toStoreID,
utils.DefaultTimeValue,
}
sql += sqlCatAndSku
sqlParams = append(sqlParams, sqlCatAndSkuParams)
globals.SugarLogger.Debug(sql)
num, err = dao.ExecuteSQL(db, sql, sqlParams)
globals.SugarLogger.Debugf("CopyStoreSkus trackInfo:%s num2:%d", ctx.GetTrackInfo(), num)
if err != nil {
return 0, err
}
// 添加toStore中不存在但fromStore存在的
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, wsc_sync_status, ebai_sync_status, mtwm_sync_status)
SELECT ?, ?, ?, ?, ?,
t1.sku_id, 0, IF(t1.price * ? / 100 > 0, t1.price * ? / 100, 1), IF(t1.unit_price * ? / 100 > 0, t1.unit_price * ? / 100, 1), t1.status, ?, ?, ?, ?, ?
FROM store_sku_bind t1
JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ?
JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ?
LEFT JOIN sku_category t4 ON t3.category_id = t4.id AND t4.deleted_at = ?
LEFT JOIN store_sku_bind t0 ON t1.sku_id = t0.sku_id AND t0.store_id = ? AND t0.deleted_at = ?
WHERE t1.store_id = ? AND t1.deleted_at = ?
`
sqlParams = []interface{}{
now, now, userName, utils.DefaultTimeValue, toStoreID,
pricePercentage,
pricePercentage,
pricePercentage,
pricePercentage,
model.SyncFlagNewMask,
model.SyncFlagNewMask,
model.SyncFlagNewMask,
model.SyncFlagNewMask,
model.SyncFlagNewMask,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
toStoreID,
utils.DefaultTimeValue,
fromStoreID,
utils.DefaultTimeValue,
}
sql += sqlCatAndSku + " AND t0.id IS NULL"
sqlParams = append(sqlParams, sqlCatAndSkuParams)
num, err = dao.ExecuteSQL(db, sql, sqlParams)
if err != nil {
return 0, err
}
globals.SugarLogger.Debugf("CopyStoreSkus trackInfo:%s num3:%d", ctx.GetTrackInfo(), num)
dao.Commit(db)
return num, err
}
func shouldPendingStorePriceChange(ctx *jxcontext.Context, storeID int, skuBindInfo *StoreSkuBindInfo) (shouldPending bool, err error) {
if globals.EnablePendingChange {
if skuBindInfo.IsFocus != 1 && (ctx.GetLoginType() == weixin.LoginType || ctx.GetLoginType() == weixin.LoginTypeMiniProgram || ctx.GetUserName() == "fakeboss") {
db := dao.GetDB()
store := &model.Store{}
store.ID = storeID
if err = dao.GetEntity(db, store); err != nil {
return false, err
}
return store.ChangePriceType == model.StoreChangePriceTypeNeedApprove, nil
}
}
return false, nil
}
func filterStorePriceChange(ctx *jxcontext.Context, storeIDs []int, skuBindInfos []*StoreSkuBindInfo) (filteredStoreIDs []int, filteredSkuBindInfos []*StoreSkuBindInfo, err error) {
globals.SugarLogger.Debug("filterStorePriceChange")
if globals.EnablePendingChange {
db := dao.GetDB()
dao.Begin(db)
defer dao.Rollback(db)
for _, storeID := range storeIDs {
for _, skuBindInfo := range skuBindInfos {
shouldPending, err2 := shouldPendingStorePriceChange(ctx, storeID, skuBindInfo)
if err = err2; err != nil {
return nil, nil, err
}
if shouldPending && (skuBindInfo.UnitPrice != 0 || skuBindInfo.IsFocus == 1) {
var (
opInfoList []*StoreOpRequestInfo
sql string
sqlParams []interface{}
opType int8
)
if skuBindInfo.IsFocus == 1 {
opType = model.RequestTypeFocusSkuName
sql = `
SELECT DISTINCT t1.*, t3.unit_price
FROM store_op_request t1
JOIN sku t2 ON t2.name_id = t1.item_id AND t2.deleted_at = ?
LEFT JOIN store_sku_bind t3 ON t3.store_id = t1.store_id AND t3.sku_id = t2.id AND t3.deleted_at = ?
WHERE t1.store_id = ? AND t1.item_id = ? AND t1.deleted_at = ? AND t1.type IN (?, ?)`
sqlParams = []interface{}{
utils.DefaultTimeValue,
utils.DefaultTimeValue,
storeID,
skuBindInfo.NameID,
utils.DefaultTimeValue,
model.RequestTypeChangePrice,
model.RequestTypeFocusSkuName,
}
} else {
opType = model.RequestTypeChangePrice
sql = `
SELECT DISTINCT t3.*, t1.unit_price
FROM store_sku_bind t1
JOIN sku t2 ON t2.id = t1.sku_id AND t2.name_id = ? AND t2.deleted_at = ?
LEFT JOIN store_op_request t3 ON t3.store_id = t1.store_id AND t3.item_id = t2.name_id AND t3.deleted_at = ? AND t3.type IN (?, ?)
WHERE t1.store_id = ? AND t1.deleted_at = ?`
sqlParams = []interface{}{
skuBindInfo.NameID,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
model.RequestTypeChangePrice,
model.RequestTypeFocusSkuName,
storeID,
utils.DefaultTimeValue,
}
}
if err = dao.GetRows(db, &opInfoList, sql, sqlParams...); err != nil {
return nil, nil, err
}
if len(opInfoList) > 1 {
panic(fmt.Sprintf("filterStorePriceChange more than one row, storeID:%d, skuBindInfo:%s, result:%s", storeID, utils.Format4Output(skuBindInfo, false), utils.Format4Output(opInfoList, false)))
}
existRow := len(opInfoList) == 1
existRequestOp := existRow && opInfoList[0].ID != 0
var changeReq *model.StoreOpRequest
if existRequestOp {
if opInfoList[0].Type != opType {
return nil, nil, fmt.Errorf("filterStorePriceChange关注与修改价格只应该存在一个待审核请求已存在的:%s新来的,storeID:%d, skuBindInfo:%s", utils.Format4Output(opInfoList[0], false), storeID, utils.Format4Output(skuBindInfo, false))
}
changeReq = &opInfoList[0].StoreOpRequest
} else {
changeReq = &model.StoreOpRequest{}
}
if existRequestOp && opInfoList[0].UnitPrice == skuBindInfo.UnitPrice {
changeReq.Status = model.RequestStatusCanceled
changeReq.DeletedAt = time.Now()
} else {
changeReq.Status = model.RequestStatusNew
changeReq.Type = opType
changeReq.StoreID = storeID
changeReq.ItemID = skuBindInfo.NameID
changeReq.UserID = ctx.GetUserName()
changeReq.IntParam1 = skuBindInfo.UnitPrice
changeReq.IntParam2 = skuBindInfo.IsSale
if len(skuBindInfo.Skus) > 0 {
changeReq.JsonParam = string(utils.MustMarshal(skuBindInfo.Skus))
}
}
if existRequestOp {
dao.WrapUpdateULEntity(changeReq, ctx.GetUserName())
if _, err = dao.UpdateEntity(db, changeReq); err != nil {
return nil, nil, err
}
} else {
if !existRow || opInfoList[0].UnitPrice != skuBindInfo.UnitPrice {
dao.WrapAddIDCULDEntity(changeReq, ctx.GetUserName())
if err = dao.CreateEntity(db, changeReq); err != nil {
return nil, nil, err
}
}
}
// 去除价格相关的部分
if skuBindInfo.IsFocus == 1 {
skuBindInfo.IsFocus = 0
}
skuBindInfo.UnitPrice = 0
}
}
}
dao.Commit(db)
}
return storeIDs, skuBindInfos, nil
}
func AcceptStoreOpRequests(ctx *jxcontext.Context, reqIDs []int) (err error) {
if globals.EnablePendingChange {
if len(reqIDs) > 0 {
subErrors := make(map[int]error)
infoMap, err2 := getStoreOpRequestsInfo(reqIDs)
if err = err2; err != nil {
return err
}
for reqID, op := range infoMap {
if op.Status == model.RequestStatusNew {
skuBindInfo := &StoreSkuBindInfo{
NameID: op.ItemID,
UnitPrice: op.IntParam1,
IsSale: op.IntParam2,
}
if op.Type == model.RequestTypeFocusSkuName {
skuBindInfo.IsFocus = 1
}
if op.JsonParam != "" {
if err2 = utils.UnmarshalUseNumber([]byte(op.JsonParam), &skuBindInfo.Skus); err2 != nil {
subErrors[reqID] = err2
}
}
if err2 == nil {
_, err2 := UpdateStoresSkus(ctx, []int{op.StoreID}, []*StoreSkuBindInfo{skuBindInfo}, false, false)
isLocalSucess := true
if err2 != nil {
subErrors[reqID] = err2
if !isSyncError(err2) {
isLocalSucess = false
}
}
if isLocalSucess {
weixinmsg.NotifyStoreOpRequestStatus(true, op.StoreID, op.ItemID, jxutils.ComposeSpuName(op.SkuNamePrefix, op.SkuNameName, 0), op.UnitPrice, op.IntParam1, "")
if err2 := changeStoreOpStatus(ctx, []int{reqID}, model.RequestStatusAccepted, ""); err2 != nil {
subErrors[reqID] = err2
}
}
}
}
}
if len(subErrors) > 0 {
errMsg := ""
for k, v := range subErrors {
errMsg += fmt.Sprintf("req:%d, error:%s\n", k, v.Error())
}
err = errors.New(errMsg)
}
}
}
return err
}
func RejectStoreOpRequests(ctx *jxcontext.Context, reqIDs []int, rejectReason string) (err error) {
infoMap, err := getStoreOpRequestsInfo(reqIDs)
if err != nil {
return err
}
if err = changeStoreOpStatus(ctx, reqIDs, model.RequestStatusRejected, rejectReason); err == nil {
for _, info := range infoMap {
weixinmsg.NotifyStoreOpRequestStatus(false, info.StoreID, info.ItemID, jxutils.ComposeSpuName(info.SkuNamePrefix, info.SkuNameName, 0), info.UnitPrice, info.IntParam1, rejectReason)
}
}
return err
}
// 当前些函数只针对type为 RequestTypeChangePrice与RequestTypeFocusSkuName的查询才有效
func GetStoreOpRequests(ctx *jxcontext.Context, fromTime, toTime time.Time, keyword string, storeIDs, itemIDs, typeList, statusList []int, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
if globals.EnablePendingChange {
sql := `
SELECT SQL_CALC_FOUND_ROWS
t1.id, t1.created_at, t1.updated_at, t1.last_operator, t1.deleted_at,
t1.type, t1.store_id, t1.item_id, t1.status, t1.user_id, t1.int_param1, t1.int_param2, t1.remark,
t2.name store_name, t3.prefix sku_name_prefix, t3.name sku_name_name, MAX(IF(t1.status = ?, t5.unit_price, t1.int_param0)) unit_price
FROM store_op_request t1
JOIN store t2 ON t1.store_id = t2.id
JOIN sku_name t3 ON t1.item_id = t3.id AND t3.deleted_at = ?
JOIN sku t4 ON t3.id = t4.name_id AND t4.deleted_at = ?
LEFT JOIN store_sku_bind t5 ON t1.store_id = t5.store_id AND t4.id = t5.sku_id AND t5.deleted_at = ?
WHERE 1 = 1`
sqlParams := []interface{}{
model.RequestStatusNew,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
}
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += " AND ( t2.name LIKE ? OR t3.name LIKE ?"
sqlParams = append(sqlParams, keywordLike, keywordLike)
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
sql += " OR t1.store_id = ? OR t1.item_id = ?"
sqlParams = append(sqlParams, keywordInt64, keywordInt64)
}
sql += ")"
}
if fromTime != utils.DefaultTimeValue {
sql += " AND t1.created_at >= ?"
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.DefaultTimeValue {
sql += " AND t1.created_at <= ?"
sqlParams = append(sqlParams, toTime)
}
if len(storeIDs) > 0 {
sql += " AND t1.store_id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, storeIDs)
}
if len(itemIDs) > 0 {
sql += " AND t1.item_id IN (" + dao.GenQuestionMarks(len(itemIDs)) + ")"
sqlParams = append(sqlParams, itemIDs)
}
if len(typeList) > 0 {
sql += " AND t1.type IN (" + dao.GenQuestionMarks(len(typeList)) + ")"
sqlParams = append(sqlParams, typeList)
}
if len(statusList) > 0 {
sql += " AND t1.status IN (" + dao.GenQuestionMarks(len(statusList)) + ")"
sqlParams = append(sqlParams, statusList)
}
sql += `
GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
ORDER BY 1 DESC
LIMIT ? OFFSET ?`
pageSize = jxutils.FormalizePageSize(pageSize)
sqlOffset := offset
sqlPageSize := pageSize
sqlParams = append(sqlParams, sqlPageSize, sqlOffset)
db := dao.GetDB()
// globals.SugarLogger.Debug(sql)
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
var requestList []*StoreOpRequestInfo
dao.Begin(db)
defer dao.Commit(db)
if err = dao.GetRows(db, &requestList, sql, sqlParams...); err == nil {
return &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount(db),
Data: requestList,
}, nil
}
}
return nil, err
}
func getStoreOpRequestsInfo(reqIDs []int) (infoMap map[int]*StoreOpRequestInfo, err error) {
infoMap = make(map[int]*StoreOpRequestInfo)
if len(reqIDs) > 0 {
sql := `
SELECT DISTINCT t1.*, t4.name store_name, t2.prefix sku_name_prefix, t2.name sku_name_name, t3.unit_price
FROM store_op_request t1
JOIN sku_name t2 ON t2.id = t1.item_id
JOIN sku t5 ON t5.name_id = t1.item_id AND t5.deleted_at = ?
LEFT JOIN store_sku_bind t3 ON t3.store_id = t1.store_id AND t3.sku_id = t5.id AND t3.deleted_at = ?
JOIN store t4 ON t4.id = t1.store_id
WHERE t1.id IN (` + dao.GenQuestionMarks(len(reqIDs)) + ")"
sqlParams := []interface{}{
utils.DefaultTimeValue,
utils.DefaultTimeValue,
reqIDs,
}
db := dao.GetDB()
var infoList []*StoreOpRequestInfo
if err = dao.GetRows(db, &infoList, sql, sqlParams...); err == nil {
for _, v := range infoList {
infoMap[v.ID] = v
}
if len(reqIDs) > len(infoMap) {
missingReqIDs := []int{}
for _, reqID := range reqIDs {
if infoMap[reqID] == nil {
missingReqIDs = append(missingReqIDs, reqID)
}
}
err = fmt.Errorf("不能找到如下的请求ID:%s", utils.Format4Output(missingReqIDs, true))
}
}
} else {
err = errors.New("没有找到指定的请求ID")
}
return infoMap, err
}
func changeStoreOpStatus(ctx *jxcontext.Context, reqIDs []int, status int8, rejectReason string) (err error) {
globals.SugarLogger.Debugf("changeStoreOpStatus, reqIDs:%v", reqIDs)
if globals.EnablePendingChange {
if len(reqIDs) > 0 {
infoMap, err2 := getStoreOpRequestsInfo(reqIDs)
if err = err2; err != nil {
return err
}
db := dao.GetDB()
dao.Begin(db)
defer dao.Rollback(db)
for _, reqID := range reqIDs {
op := &model.StoreOpRequest{}
op.Remark = rejectReason
op.Status = status
if infoMap[reqID] != nil {
op.IntParam0 = infoMap[reqID].UnitPrice
}
dao.WrapUpdateULEntity(op, ctx.GetUserName())
op.DeletedAt = time.Now()
op.ID = reqID
// globals.SugarLogger.Debug(utils.Format4Output(op, false))
if _, err = dao.UpdateEntity(db, op, "IntParam0", "Remark", "Status", "DeletedAt", "LastOperator", "UpdatedAt"); err != nil {
return err
}
}
dao.Commit(db)
}
}
return err
}
func setStoreSkuBindStatus(skuBind *model.StoreSkuBind, status int8) {
skuBind.JdSyncStatus |= status
skuBind.ElmSyncStatus |= status
skuBind.EbaiSyncStatus |= status
skuBind.MtwmSyncStatus |= status
skuBind.WscSyncStatus |= status
}
func checkStoreExisting(db *dao.DaoDB, storeID int) (err error) {
store := &model.Store{}
store.ID = storeID
if err = dao.GetEntity(db, store); err != nil {
if err == orm.ErrNoRows {
return fmt.Errorf("门店:%d不存在", storeID)
}
return err
}
return nil
}
func RefreshStoresSkuByVendor(ctx *jxcontext.Context, storeIDs []int, vendorID int, isAsync bool) (hint string, err error) {
if vendorID != model.VendorIDJD {
return "", fmt.Errorf("此功能当前只支持京东到家平台")
}
db := dao.GetDB()
storeMapList, err := dao.GetStoresMapList(db, nil, storeIDs, model.StoreStatusAll)
if err != nil {
return "", err
}
if len(storeMapList) != len(storeIDs) {
return "", fmt.Errorf("门店绑定信息不匹配,请确定门店绑定且只绑定了京东平台")
}
storeMap := make(map[int]*model.StoreMap)
for _, v := range storeMapList {
if v.VendorID != vendorID {
return "", fmt.Errorf("门店%d绑定的不是京东", v.StoreID)
}
storeMap[v.StoreID] = v
}
handler := partner.GetPurchasePlatformFromVendorID(vendorID)
var storeSkuList []*model.StoreSkuBind
rootTask := tasksch.NewSeqTask(fmt.Sprintf("根据厂家门店商品信息相应刷新本地数据:%v", storeIDs), ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
storeSkuList, err = handler.GetStoresSku(ctx, task, storeIDs)
case 1:
if len(storeSkuList) > 0 {
var skuList []*model.SkuAndName
skuList, err = dao.GetSkus(db, nil, nil, nil, nil)
if err == nil {
skuNameMap := make(map[int]*model.SkuName)
skuMap := make(map[int]*model.SkuAndName)
for _, sku := range skuList {
if skuNameMap[sku.NameID] == nil {
skuNameMap[sku.NameID] = &model.SkuName{
Unit: sku.Unit,
}
}
skuMap[sku.ID] = sku
}
for _, v := range storeSkuList {
sku := skuMap[v.SkuID]
skuName := skuNameMap[sku.NameID]
if skuName.IsGlobal == 0 && (jxutils.IsSkuSpecial(sku.SpecQuality, sku.SpecUnit) || skuName.Unit != model.SpecialUnit) {
skuName.Price = v.Price
skuName.IsGlobal = 1 // 标准价
}
}
for _, v := range storeSkuList {
sku := skuMap[v.SkuID]
skuName := skuNameMap[sku.NameID]
if skuName.IsGlobal == 0 {
if skuName.Price == 0 {
skuName.Price = jxutils.CaculateUnitPrice(v.Price, sku.SpecQuality, sku.SpecUnit, skuName.Unit)
} else {
skuName.Price = (skuName.Price + jxutils.CaculateUnitPrice(v.Price, sku.SpecQuality, sku.SpecUnit, skuName.Unit)) / 2
}
}
}
for _, v := range storeSkuList {
pricePercentage := int(storeMap[v.StoreID].PricePercentage)
skuName := skuNameMap[skuMap[v.SkuID].NameID]
v.Price = jxutils.CaculateSkuPriceFromVendor(v.Price, pricePercentage, 0)
v.UnitPrice = jxutils.CaculateSkuPriceFromVendor(skuName.Price, pricePercentage, 0)
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
setStoreSkuBindStatus(v, model.SyncFlagNewMask)
v.JdSyncStatus = 0
}
}
}
case 2:
if len(storeSkuList) > 0 {
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
if _, err = dao.ExecuteSQL(db, `
DELETE t1
FROM store_sku_bind t1
WHERE t1.store_id IN (
`+dao.GenQuestionMarks(len(storeIDs))+")", storeIDs); err == nil {
if err = dao.CreateMultiEntities(db, storeSkuList); err == nil {
hint = utils.Int2Str(len(storeSkuList))
dao.Commit(db)
}
}
}
}
return nil, err
}, 3)
tasksch.ManageTask(rootTask).Run()
if isAsync {
hint = rootTask.GetID()
} else {
_, err = rootTask.GetResult(0)
}
return hint, err
}
func GetVendorStoreSkusInfo(ctx *jxcontext.Context, storeID int, vendorIDs, skuIDs []int, isContinueWhenError bool) (skuVendorMap map[int][]*partner.BareStoreSkuInfo, err error) {
globals.SugarLogger.Debugf("GetVendorStoreSkusInfo, storeID:%d, vendorIDs:%v, skuID:%v", storeID, vendorIDs, skuIDs)
db := dao.GetDB()
var locker sync.RWMutex
skuVendorMap = make(map[int][]*partner.BareStoreSkuInfo)
_, err = CurVendorSync.LoopStoresMap(ctx, db, fmt.Sprintf("GetVendorStoreSkusInfo storeID:%d", storeID), false, false, vendorIDs, []int{storeID},
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
if handler := CurVendorSync.GetStoreHandler(loopMapInfo.VendorID); handler != nil {
storeSkuList, err2 := dao.GetStoreSkus2(db, loopMapInfo.VendorID, storeID, skuIDs, false)
if err = err2; err == nil && len(storeSkuList) > 0 {
bareStoreSkuInfoList := make([]*partner.BareStoreSkuInfo, len(skuIDs))
for k, v := range storeSkuList {
bareStoreSkuInfoList[k] = &partner.BareStoreSkuInfo{
SkuID: v.SkuID,
VendorSkuID: v.VendorSkuID,
}
}
outBareStoreSkuInfoList, err2 := handler.GetStoreSkusInfo(ctx, t, loopMapInfo.StoreMapList[0].StoreID, loopMapInfo.StoreMapList[0].VendorStoreID, bareStoreSkuInfoList)
if err = err2; err == nil && outBareStoreSkuInfoList != nil {
locker.Lock()
defer locker.Unlock()
skuVendorMap[loopMapInfo.VendorID] = outBareStoreSkuInfoList
}
}
}
return nil, err
}, true)
if err != nil {
skuVendorMap = nil
}
return skuVendorMap, err
}
func SyncJdStoreProducts(ctx *jxcontext.Context, storeIDs, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
db := dao.GetDB()
isManageIt := len(storeIDs) != 1 || len(skuIDs) == 0 || len(skuIDs) > 8
hint, err = CurVendorSync.LoopStoresMap(ctx, db, fmt.Sprintf("京东商家商品状态同步:%v", storeIDs), isAsync, isManageIt, []int{model.VendorIDJD}, storeIDs,
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
if handler := partner.GetPurchasePlatformFromVendorID(loopMapInfo.VendorID); handler != nil {
jdHandler := handler.(*jd.PurchaseHandler)
hint, err2 := jdHandler.SyncStoreProducts(ctx, t, loopMapInfo.StoreMapList[0].StoreID, skuIDs, false, isContinueWhenError)
if err = err2; err == nil {
retVal = []interface{}{hint}
}
}
return retVal, partner.AddVendorInfo2Err(err, loopMapInfo.VendorID)
}, isContinueWhenError)
return hint, err
}
func GetMissingStoreSkuFromOrder(ctx *jxcontext.Context, fromTime time.Time) (missingList []*StoreSkuBindInfo, err error) {
storeSkuList, err := dao.GetMissingStoreSkuFromOrder(dao.GetDB(), nil, fromTime)
if err == nil {
storeSkuNameMap := make(map[int64]*StoreSkuBindInfo)
for _, v := range storeSkuList {
skuName := storeSkuNameMap[jxutils.Combine2Int(v.StoreID, v.NameID)]
if skuName == nil {
skuName = &StoreSkuBindInfo{
StoreID: v.StoreID,
NameID: v.NameID,
IsFocus: 1,
IsSale: 1,
// 这里没有考虑平台价格比例
UnitPrice: jxutils.CaculateUnitPrice(v.RefPrice, v.SpecQuality, v.SpecUnit, v.Unit),
}
missingList = append(missingList, skuName)
}
skuName.Skus = append(skuName.Skus, &StoreSkuBindSkuInfo{
SkuID: v.SkuID,
})
}
}
return missingList, err
}