Files
jx-callback/business/jxstore/cms/store_sku.go
苏尹岚 e61db3ce10 aa
2021-03-25 17:38:41 +08:00

5518 lines
192 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"
"io"
"math"
"mime/multipart"
"sort"
"strconv"
"strings"
"sync"
"time"
"unicode"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/jx-callback/business/auth2"
"github.com/astaxie/beego"
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/globals/refutil"
"git.rosy.net.cn/jx-callback/business/jxstore/event"
"git.rosy.net.cn/jx-callback/business/jxstore/permission"
"git.rosy.net.cn/baseapi"
"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/jx-callback/business/partner/purchase/jd"
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/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/360EntSecGroup-Skylar/excelize"
"github.com/astaxie/beego/orm"
)
const (
MaxSkuUnitPrice = 500000
CopyStoreSkuModeFresh = "fresh" // 全新复制
CopyStoreSkuModeUpdate = "update" // 增量复制
CopyStoreSkuModeUpdatePrice = "updatePrice" // 增量复制价格
upcSpecName1 = "(新老包装随机发货)"
)
//通用写入Excel
type ExcelParam struct {
DataList interface{}
SheetName string
TitleList []string
}
// UpdateStoreSku用API调用时
type StoreSkuBindSkuInfo struct {
SkuID int `json:"skuID"`
IsSale int `json:"isSale,omitempty"` // -1不可售0忽略1可售
Stock *int `json:"stock"`
// 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"`
StatusSaleBegin int16 `json:"statusSaleBegin" validate:"max=2359,min=1,ltfield=StatusSaleEnd"` //商品可售时间范围
StatusSaleEnd int16 `json:"statusSaleEnd" validate:"max=2359,min=1"`
UPC string `json:"upc"`
Skus []*StoreSkuBindSkuInfo `json:"skus,omitempty"`
}
type tStoreSkuBindAndSpec struct {
model.StoreSkuBind
SkuStatus int
SkuNameStatus int
Name string
SpecQuality float32
SpecUnit string
SkuNamePrice int
SkuNameUnit string
RealSkuID int `orm:"column(real_sku_id)"`
ExdSkuID string `orm:"column(exd_sku_id)"`
StoreName string
ChangePriceType int8 `json:"changePriceType"` // 修改价格类型,即是否需要审核
NameID int `orm:"column(name_id)" json:"nameID"`
}
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"`
}
type tStoreNameBind struct {
StoreID int `orm:"column(store_id)"`
NameID int `orm:"column(name_id)"`
Name string
}
type tGetStoresSkusInfo struct {
StoreID int `orm:"column(store_id)"`
StoreName string
model.SkuName
PayPercentage int `json:"-"`
dao.StoreSkuExt
RealMidUnitPrice int `json:"realMidUnitPrice"` //真实的该商品的全国中位价
YbSkuName string
AuditUnitPrice int
}
type SheetParam struct {
OutSkuIDCol int
SkuNameIDCol int
SkuPriceCol int
SkuNameCol int
SkuUnitCol int
SkuRow int
}
type DataVendorStoreSkuPrice struct {
StoreID string `json:"门店ID"`
StoreName string `json:"门店名"`
SkuID int `json:"商品ID"`
SkuName string `json:"商品名"`
VendorPrice string `json:"平台价"`
}
type DataSuccess struct {
NameID int `json:"商品NameID"`
Name string `json:"商品名称"`
Unit string `json:"单位"`
OrgPrice float64 `json:"原价"`
NowPrice float64 `json:"现价"`
MixPrice float64 `json:"涨跌"`
}
type DataFailed struct {
NameID int `json:"商品NameID"`
Name string `json:"商品名称"`
Comment string `json:"备注"`
}
type DataLock struct {
dataSuccessList []DataSuccess
dataFailedList []DataFailed
locker sync.RWMutex
}
type tUpdateStoresSkus struct {
StoreID int
SkuBindInfos []*StoreSkuBindInfo
}
type tStoreSkusSecKill struct {
StoreID int `orm:"column(store_id)"`
VendorID int `orm:"column(vendor_id)"`
SecKillCount int
SecKillCount2 int
OperatorPhoneList []string
MarketManPhone string
NoticeMsg string
}
type JdStoreSkus struct {
JdStoreID int `json:"jdStoreID"`
JdSkuID int `json:"jdSkuID"`
Price int `json:"price"`
}
type tUpdateSkuSpecTag struct {
StoreID int `json:"storeID"`
SkuID int `json:"skuID"`
IsSpec int `json:"isSpec"`
}
type MatterStock struct {
SkuID int `json:"skuID"`
SkuNameID int `json:"skuNameID"`
Name string `json:"name"`
Stock int `json:"stock"`
}
type ActStoreSkuParam struct {
model.ActStoreSku
ActualActPrice int64 `json:"actualActPrice,omitempty"` // 单品级活动用,创建活动时商品的活动价格
VendorPrice int64 `json:"vendorPrice,omitempty"` // 创建活动时的平台价格
ErrMsg string `json:"errMsg,omitempty"`
}
const (
maxStoreNameBind = 10000 // 最大门店SkuName bind个数
maxStoreNameBind2 = 10000 // 最大门店乘SkuName个数
AutoSaleAtStr = "22:00:00"
)
var (
asyncOpMobileMap = map[string]int{
"18982250714": 1, // 老赵
"18180948107": 1, // 徐
// "13684045763": 1, // 周
}
dataLock DataLock
titleListVendorStoreSkuPrice = []string{
"门店ID",
"门店名",
"商品ID",
"商品名",
"平台价",
}
titleListSuccess = []string{
"商品NameID",
"商品名称",
"单位",
"原价",
"现价",
"涨跌",
}
titleListFailed = []string{
"商品NameID",
"商品名称",
"备注",
}
autoNotFoucsStoreMap = map[int]int{
667088: 667088,
model.MatterStoreID: model.MatterStoreID,
103038: 103038,
300397: 300397,
}
)
func GetStoresSkusForStore(ctx *jxcontext.Context, storeID int, isFocus, isAct bool, keyword string, categoryID, status, offset, pageSize int) (skuNamesInfo *dao.StoreSkuNamesInfo, err error) {
//权限
if permission.IsRoled(ctx) {
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
if storeIDsMap[storeID] == 0 {
return skuNamesInfo, err
}
}
}
var (
sqlParams []interface{}
db = dao.GetDB()
SkuNames []*dao.StoreSkuNameExt
)
sql := `
SELECT SQL_CALC_FOUND_ROWS DISTINCT a.*, e.id store_id
FROM sku_name a
JOIN sku b ON b.name_id = a.id AND b.deleted_at = ?
JOIN store e ON e.deleted_at = ? AND e.id = ?
`
sqlParams = append(sqlParams,
utils.DefaultTimeValue,
utils.DefaultTimeValue, storeID,
)
if !isFocus {
sql += `
LEFT
`
}
sql += `
JOIN store_sku_bind c ON c.sku_id = b.id AND c.deleted_at = ? AND c.store_id = e.id
`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if status != -1 {
sql += " AND c.status = ?"
sqlParams = append(sqlParams, status)
}
sql += `
LEFT JOIN sku_category d ON d.id = a.category_id AND d.deleted_at = ?
LEFT JOIN sku_name_place_bind f ON a.id = f.name_id AND e.city_code = f.place_code
`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if categoryID != 0 {
sql += " AND d.id = ?"
sqlParams = append(sqlParams, categoryID)
}
if isAct {
sql += `
JOIN (
SELECT t2.store_id, t2.sku_id,
MIN(IF(t3.actual_act_price <= 0, NULL, t3.actual_act_price)) actual_act_price, /*non-zero min value*/
MIN(IF(t2.earning_price <= 0, NULL, t2.earning_price)) earning_price /*non-zero min value*/
FROM act t1
JOIN act_store_sku t2 ON t2.act_id = t1.id AND t2.deleted_at = ?
JOIN act_store_sku_map t3 ON t3.bind_id = t2.id AND t3.act_id = t1.id AND (t3.sync_status & ? = 0 OR t1.type = ?)
JOIN act_map t4 ON t4.act_id = t1.id AND t4.vendor_id = t3.vendor_id AND t4.deleted_at = ? AND (t4.sync_status & ? = 0 OR t1.type = ?)
WHERE t1.deleted_at = ? AND t1.status = ? AND NOT (t1.begin_at > ? OR t1.end_at < ?)
AND t2.store_id = ?
GROUP BY 1,2
) ta ON ta.store_id = e.id AND ta.sku_id = b.id
`
sqlParams = append(sqlParams,
utils.DefaultTimeValue,
model.SyncFlagNewMask,
model.ActSkuFake,
utils.DefaultTimeValue,
model.SyncFlagNewMask,
model.ActSkuFake,
utils.DefaultTimeValue,
model.ActStatusCreated,
time.Now(),
time.Now(),
storeID,
)
}
sql += `
WHERE a.deleted_at = ?
AND (a.is_global = 1 OR f.id IS NOT NULL OR 1 = ?)
`
sqlParams = append(sqlParams, utils.DefaultTimeValue, utils.Bool2Int(isFocus))
if isFocus {
sql += " AND ((a.status = ? AND b.status = ?) OR c.status = ?)"
sqlParams = append(sqlParams, model.SkuStatusNormal, model.SkuStatusNormal, model.SkuStatusNormal)
} else {
sql += " AND c.sku_id IS NULL AND (a.status = ? AND b.status = ?)"
sqlParams = append(sqlParams, model.SkuStatusNormal, model.SkuStatusNormal)
}
if keyword != "" {
sql += " AND a.name LIKE ?"
sqlParams = append(sqlParams, "%"+keyword+"%")
}
sql += `
LIMIT ? OFFSET ?
`
pageSize = jxutils.FormalizePageSize(pageSize)
offset = jxutils.FormalizePageOffset(offset)
sqlParams = append(sqlParams, pageSize, offset)
fmt.Println(sql)
fmt.Println(sqlParams)
dao.Begin(db)
defer dao.Commit(db)
if err = dao.GetRows(db, &SkuNames, sql, sqlParams...); err == nil {
skuNamesInfo = &dao.StoreSkuNamesInfo{
TotalCount: dao.GetLastTotalRowCount(db),
}
// skuNamesInfo.TotalCount = dao.GetLastTotalRowCount(db)
for _, v := range SkuNames {
var skus []*dao.StoreSkuExt
sql2 := `
SELECT a.*, b.status store_sku_status
FROM sku a
JOIN store_sku_bind b ON a.id = b.sku_id AND b.deleted_at = ? AND b.store_id = ?
JOIN sku_name c ON a.name_id = c.id AND c.deleted_at = ? AND c.status = ?
WHERE a.deleted_at = ? AND a.name_id = ? AND a.status = ?
`
sqlParams2 := []interface{}{utils.DefaultTimeValue, storeID,
utils.DefaultTimeValue, model.SkuStatusNormal,
utils.DefaultTimeValue, v.ID, model.SkuStatusNormal,
}
if status != -1 {
sql2 += " AND b.status = ?"
sqlParams2 = append(sqlParams2, status)
}
if err = dao.GetRows(db, &skus, sql2, sqlParams2); err == nil {
v.Skus = skus
}
}
skuNamesInfo.SkuNames = SkuNames
if err == nil {
if isFocus {
if err == nil {
storeIDs, skuIDs := GetStoreAndSkuIDsFromInfo(skuNamesInfo)
err = dao.UpdateActPrice4StoreSkuNameNew(db, storeIDs, skuIDs, skuNamesInfo, -1)
}
} else {
err = updateUnitPrice4StoreSkuNameNew(db, skuNamesInfo)
}
}
}
return skuNamesInfo, err
}
func GetStoreSkus(ctx *jxcontext.Context, storeID int, skuIDs []int, isFocus bool, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *dao.StoreSkuNamesInfo, err error) {
return GetStoresSkus(ctx, []int{storeID}, skuIDs, nil, isFocus, false, 0, keyword, isBySku, isAct, params, offset, pageSize)
}
func getGetStoresSkusBaseSQL(db *dao.DaoDB, storeIDs, skuIDs []int, upcs []string, isFocus bool, keyword string, isBySku, isAct, isHighPrice bool, priceType int, actVendorID int, params map[string]interface{}) (sql string, sqlParams []interface{}, err error) {
sql = `
FROM sku_name t1
JOIN sku t2 FORCE INDEX(PRIMARY) ON t1.id = t2.name_id AND t2.deleted_at = ?/* AND t2.status = ?*/
JOIN store t3 ON t3.deleted_at = ?
LEFT JOIN store_map sm ON sm.store_id = t3.id AND sm.vendor_id = ? AND sm.deleted_at = ?
LEFT JOIN store_map smm ON smm.store_id = t3.id AND smm.deleted_at = ? AND smm.vendor_id = ?
LEFT JOIN thing_map t2m ON t2m.thing_type = ? AND t2m.thing_id = t2.id AND t2m.vendor_id = sm.vendor_id AND t2m.vendor_org_code = sm.vendor_org_code AND t2m.deleted_at = ?
`
sqlParams = []interface{}{
utils.DefaultTimeValue,
// model.SkuStatusNormal,
utils.DefaultTimeValue,
model.VendorIDJD, utils.DefaultTimeValue, // TODO 这里直接用JD有问题
utils.DefaultTimeValue, model.VendorIDYB,
model.ThingTypeSku, utils.DefaultTimeValue,
}
if isFocus {
if isAct {
sql += `
JOIN (
SELECT t2.store_id, t2.sku_id,
MIN(IF(t3.actual_act_price <= 0, NULL, t3.actual_act_price)) actual_act_price, /*non-zero min value*/
MIN(IF(t2.earning_price <= 0, NULL, t2.earning_price)) earning_price /*non-zero min value*/
FROM act t1
JOIN act_store_sku t2 ON t2.act_id = t1.id AND t2.deleted_at = ?
JOIN act_store_sku_map t3 ON t3.bind_id = t2.id AND t3.act_id = t1.id AND (t3.sync_status & ? = 0 OR t1.type = ?)
JOIN act_map t4 ON t4.act_id = t1.id AND t4.vendor_id = t3.vendor_id AND t4.deleted_at = ? AND (t4.sync_status & ? = 0 OR t1.type = ?)
WHERE t1.deleted_at = ? AND t1.status = ? AND NOT (t1.begin_at > ? OR t1.end_at < ?)`
sqlParams = append(sqlParams, []interface{}{
utils.DefaultTimeValue,
model.SyncFlagNewMask,
model.ActSkuFake,
utils.DefaultTimeValue,
model.SyncFlagNewMask,
model.ActSkuFake,
utils.DefaultTimeValue,
model.ActStatusCreated,
time.Now(),
time.Now(),
})
if actVendorID >= 0 {
sql += " AND t1.vendor_mask & ? <> 0"
sqlParams = append(sqlParams, model.GetVendorMask(actVendorID))
}
if len(storeIDs) > 0 {
sql += " AND t2.store_id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, storeIDs)
}
if len(skuIDs) > 0 {
sql += " AND t2.sku_id IN (" + dao.GenQuestionMarks(len(skuIDs)) + ")"
sqlParams = append(sqlParams, skuIDs)
}
sql += `
GROUP BY 1,2
) ta ON ta.store_id = t3.id AND ta.sku_id = t2.id`
}
} else {
sql += " LEFT"
}
sql += `
JOIN store_sku_bind t4 ON t4.store_id = t3.id AND t4.sku_id = t2.id AND t4.deleted_at = ?
LEFT JOIN sku_name_place_bind t5 ON t1.id = t5.name_id AND t3.city_code = t5.place_code
LEFT JOIN price_refer_snapshot t6 ON t6.city_code = ? AND t6.sku_id = t2.id AND t6.snapshot_at = ?
LEFT JOIN store_sku_audit t7 ON t7.store_id = t3.id AND t7.name_id = t1.id AND t7.status = ? AND t7.deleted_at = ?
WHERE t1.deleted_at = ? AND (t1.is_global = 1 OR t5.id IS NOT NULL OR 1 = ?)/* AND t1.status = ?*/
`
sqlParams = append(sqlParams, []interface{}{
utils.DefaultTimeValue,
0, utils.Time2Date(time.Now().AddDate(0, 0, -1)),
model.StoreAuditStatusOnline, utils.DefaultTimeValue,
utils.DefaultTimeValue,
utils.Bool2Int(isFocus),
})
if isHighPrice || priceType == 1 {
sql += " AND t4.unit_price > t6.mid_unit_price / IF(t3.pay_percentage < 50 , 70, t3.pay_percentage) * 1.2 * 100"
}
if priceType == -1 {
sql += " AND t4.unit_price < t6.mid_unit_price / IF(t3.pay_percentage < 50 , 70, t3.pay_percentage) / 1.2 * 100"
}
if isFocus {
sql += " 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 (SELECT COUNT(*) FROM thing_map tm WHERE tm.vendor_org_code = sm.vendor_org_code AND tm.thing_type = ? AND tm.thing_id = t2.id AND tm.deleted_at = ? AND tm.vendor_thing_id = ?) > 0
`
sqlParams = append(sqlParams,
keywordInt64, keywordInt64,
model.ThingTypeSku, utils.DefaultTimeValue, keywordInt64)
if isFocus {
sql += " OR t4.ebai_id = ? OR t4.mtwm_id = ?"
sqlParams = append(sqlParams, 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["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 len(storeIDs) > 0 {
sql += " AND t3.id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, storeIDs)
if len(storeIDs) == 1 {
sql += " AND IF(INSTR(t3.name,'" + model.ExdStoreName + "') > 0, t2.exd_sku_id <> '', t2.exd_sku_id = '')"
}
}
if len(upcs) > 0 {
sql += " AND t1.upc IN (" + dao.GenQuestionMarks(len(upcs)) + ")"
sqlParams = append(sqlParams, upcs)
}
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 lockTimeStr, ok := params["lockTime"].(string); ok && lockTimeStr != "" {
if timeList, err2 := jxutils.BatchStr2Time(lockTimeStr); err2 == nil {
sql += " AND (t4.jd_lock_time > ? OR t4.mtwm_lock_time > ? OR t4.ebai_lock_time > ? OR t4.jx_lock_time > ?)"
sqlParams = append(sqlParams, timeList[0], timeList[0], timeList[0], timeList[0])
}
}
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 t1.status = ? AND t2.status = ?)"
sqlParams = append(sqlParams, params["jdSyncStatus"], model.SkuStatusNormal, model.SkuStatusNormal)
}
if params["ebaiSyncStatus"] != nil && realVendorMap[model.VendorIDEBAI] == 1 {
sql += " OR (t4.ebai_sync_status & ? <> 0 AND NOT (t4.ebai_sync_status & ? <> 0 AND (t4.status <> ? OR t2.status <> ?)) )"
sqlParams = append(sqlParams, params["ebaiSyncStatus"], model.SyncFlagNewMask, model.SkuStatusNormal, model.SkuStatusNormal)
}
if params["mtwmSyncStatus"] != nil && realVendorMap[model.VendorIDMTWM] == 1 {
sql += " OR (t4.mtwm_sync_status & ? <> 0 AND NOT (t4.mtwm_sync_status & ? <> 0 AND (t4.status <> ? OR t2.status <> ?)) )"
sqlParams = append(sqlParams, params["mtwmSyncStatus"], model.SyncFlagNewMask, model.SkuStatusNormal, model.SkuStatusNormal)
}
sql += ")"
}
}
if isFocus {
/*前台传入的最大值和最小值设置*/
if params["highestPrice"] != "" && params["highestPrice"] != nil {
//highestPrice := utils.Interface2Float64WithDefault(params["highestPrice"], 0) * 100
sql += " AND t4.unit_price <= ? "
sqlParams = append(sqlParams, params["highestPrice"])
}
if params["minimumPrice"] != "" && params["minimumPrice"] != nil {
//minimumPrice := utils.Interface2Float64WithDefault(params["minimumPrice"], 0) * 100
sql += " AND t4.unit_price >= ? "
sqlParams = append(sqlParams, params["minimumPrice"])
}
}
return sql, sqlParams, err
}
func GetStoresSkus(ctx *jxcontext.Context, storeIDs, skuIDs []int, upcs []string, isFocus, isHighPrice bool, priceType int, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *dao.StoreSkuNamesInfo, err error) {
//权限
if permission.IsRoled(ctx) {
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
var storeIDs2 []int
if len(storeIDs) > 0 {
for _, v := range storeIDs {
if storeIDsMap[v] != 0 {
storeIDs2 = append(storeIDs2, v)
}
}
if len(storeIDs2) == 0 {
storeIDs2 = append(storeIDs2, -1)
}
} else {
for k, _ := range storeIDsMap {
storeIDs2 = append(storeIDs2, k)
}
}
storeIDs = nil
storeIDs = storeIDs2
}
}
return GetStoresSkusNew(ctx, storeIDs, skuIDs, upcs, isFocus, isHighPrice, priceType, keyword, isBySku, isAct, params, offset, pageSize)
}
func GetStoresSkusNew(ctx *jxcontext.Context, storeIDs, skuIDs []int, upcs []string, isFocus, isHighPrice bool, priceType int, keyword string, isBySku, isAct bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *dao.StoreSkuNamesInfo, err error) {
if !isFocus && !isBySku && (len(storeIDs) > 1 || len(storeIDs) == 0) {
return nil, fmt.Errorf("未关注按SkuName只能查询单店")
}
if len(storeIDs) == 0 && len(skuIDs) == 0 && pageSize == -1 {
return nil, fmt.Errorf("GetStoresSkus必须指定storeIDs或skuIDs或分页")
}
actVendorID := -1
if params["actVendorID"] != nil {
actVendorID = int(utils.Interface2Int64WithDefault(params["actVendorID"], -1))
}
var highestPrice, minimumPrice float64
if params["highestPrice"] != nil {
if highestPrice, err = strconv.ParseFloat(params["highestPrice"].(string), 64); err != nil {
delete(params, "highestPrice")
} else {
params["highestPrice"] = highestPrice * 100
}
}
if params["minimumPrice"] != nil {
if minimumPrice, err = strconv.ParseFloat(params["minimumPrice"].(string), 64); err != nil {
delete(params, "minimumPrice")
} else {
params["minimumPrice"] = minimumPrice * 100
}
}
if !(highestPrice > 0 && highestPrice > minimumPrice) || !(highestPrice > 0) {
delete(params, "highestPrice")
}
if !(minimumPrice >= 0 && highestPrice > 0 && highestPrice > minimumPrice) || !(minimumPrice >= 0) {
delete(params, "minimumPrice")
}
db := dao.GetDB()
sql, sqlParams, err := getGetStoresSkusBaseSQL(db, storeIDs, skuIDs, upcs, isFocus, keyword, isBySku, isAct, isHighPrice, priceType, actVendorID, params)
if err != nil {
return nil, err
}
pageSize = jxutils.FormalizePageSize(pageSize)
offset = jxutils.FormalizePageOffset(offset)
sqlOffset := offset
sqlPageSize := pageSize
isSaleInfo := params["stFromTime"] != nil
if isSaleInfo {
sqlOffset = 0
sqlPageSize = jxutils.FormalizePageSize(-1)
}
sqlParamsPage := []interface{}{sqlPageSize, sqlOffset}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
catOrderBy := ""
if params["categoryID"] != nil {
catOrderBy = "t2.seq, "
}
skuNamesInfo = &dao.StoreSkuNamesInfo{}
if !isBySku && sqlPageSize != model.UnlimitedPageSize {
sql2 := `
SELECT SQL_CALC_FOUND_ROWS
t3.id store_id, t1.id name_id
` + sql + `
GROUP BY 1, 2
ORDER BY 1, 2
LIMIT ? OFFSET ?
`
sqlParams2 := append([]interface{}{}, sqlParams...)
sqlParams2 = append(sqlParams2, sqlParamsPage)
var storeNameList []*tStoreNameBind
beginTime := time.Now()
if err = dao.GetRows(db, &storeNameList, sql2, sqlParams2...); err != nil {
dao.Rollback(db)
return nil, err
}
globals.SugarLogger.Debugf("GetStoresSkusNew get result1:%v", time.Now().Sub(beginTime))
skuNamesInfo.TotalCount = dao.GetLastTotalRowCount(db)
sql += " AND (1 = 0"
for _, v := range storeNameList {
sql += " OR (t1.id = ? AND t3.id = ?)"
sqlParams = append(sqlParams, v.NameID, v.StoreID)
}
sql += fmt.Sprintf(`)
ORDER BY %s t3.id, t2.name_id, t2.id`, catOrderBy)
} else {
if isFocus {
sql += fmt.Sprintf(`
ORDER BY %s t3.id, t2.name_id, t2.id`, catOrderBy)
}
sql += `
LIMIT ? OFFSET ?`
sqlParams = append(sqlParams, sqlParamsPage)
}
sql = `
SELECT SQL_CALC_FOUND_ROWS
t3.id store_id, t3.name store_name, t3.pay_percentage,
t1.*,
t2.name_id, t2.id sku_id, t2.spec_quality sku_spec_quality, t2.spec_unit sku_spec_unit, t2.weight, t2m.vendor_thing_id sku_jd_id,
t2.comment, t2.category_id sku_category_id, t2.status sku_status, t2.eclp_id,
t4.created_at bind_created_at, t4.updated_at bind_updated_at, t4.last_operator bind_last_operator, t4.deleted_at bind_deleted_at,
t4.sub_store_id, t4.price bind_price, IF(t4.unit_price IS NOT NULL, t4.unit_price, t1.price) unit_price, t4.status store_sku_status, t4.auto_sale_at,
t4.ebai_id, t4.mtwm_id, t4.yb_id, CONCAT(smm.yb_store_prefix,t1.yb_name_suffix) yb_sku_name, t4.jds_id, t4.jds_ware_id,
t4.jd_sync_status, t4.ebai_sync_status, t4.mtwm_sync_status, t4.yb_sync_status, t4.jds_sync_status,
t4.jd_price, t4.ebai_price, t4.mtwm_price, t4.jx_price, t4.yb_price, t4.jds_price,
t4.jd_lock_time, t4.ebai_lock_time, t4.mtwm_lock_time, t4.jx_lock_time, t4.yb_lock_time, t4.jds_lock_time,
t4.status_sale_begin, t4.status_sale_end, t4.stock,
t6.mid_unit_price real_mid_unit_price,
t7.unit_price audit_unit_price
` + sql
if isHighPrice || priceType != 0 {
sql += " , t4.unit_price DESC LIMIT 99"
}
var tmpList []*tGetStoresSkusInfo
beginTime := time.Now()
if err = dao.GetRows(db, &tmpList, sql, sqlParams...); err != nil {
dao.Rollback(db)
return nil, err
}
if isBySku {
skuNamesInfo.TotalCount = dao.GetLastTotalRowCount(db)
}
dao.Commit(db)
globals.SugarLogger.Debugf("GetStoresSkusNew get result2:%v", time.Now().Sub(beginTime))
storeNameMap := make(map[int64]*dao.StoreSkuNameExt)
for _, v := range tmpList {
var storeName *dao.StoreSkuNameExt
index := jxutils.Combine2Int(v.StoreID, v.ID)
if isBySku || storeNameMap[index] == nil {
storeName = &dao.StoreSkuNameExt{
StoreID: v.StoreID,
StoreName: v.StoreName,
SkuName: v.SkuName,
UnitPrice: v.UnitPrice,
PayPercentage: v.PayPercentage,
RealMidUnitPrice: v.RealMidUnitPrice,
YbSkuName: v.YbSkuName,
AuditUnitPrice: v.AuditUnitPrice,
}
if !isBySku {
storeNameMap[index] = storeName
}
skuNamesInfo.SkuNames = append(skuNamesInfo.SkuNames, storeName)
} else {
storeName = storeNameMap[index]
}
storeName.Skus = append(storeName.Skus, &v.StoreSkuExt)
}
if err == nil {
if isFocus {
if isSaleInfo {
beginTime := time.Now()
err = updateSaleInfo4StoreSkuName(ctx, db, storeIDs, skuIDs, params, skuNamesInfo, offset, pageSize)
globals.SugarLogger.Debugf("GetStoresSkusNew updateSaleInfo4StoreSkuName:%v", time.Now().Sub(beginTime))
}
if err == nil {
if true { //!(offset == 0 && pageSize == model.UnlimitedPageSize) {
storeIDs, skuIDs = GetStoreAndSkuIDsFromInfo(skuNamesInfo)
}
beginTime := time.Now()
err = dao.UpdateActPrice4StoreSkuNameNew(db, storeIDs, skuIDs, skuNamesInfo, actVendorID)
globals.SugarLogger.Debugf("GetStoresSkusNew updateActPrice4StoreSkuName:%v", time.Now().Sub(beginTime))
}
} else {
err = updateUnitPrice4StoreSkuNameNew(db, skuNamesInfo)
}
}
// globals.SugarLogger.Debug(utils.Format4Output(skuNamesInfo, false))
return skuNamesInfo, err
}
func GetStoreAndSkuIDsFromInfo(skuNamesInfo *dao.StoreSkuNamesInfo) (storeIDs, skuIDs []int) {
storeIDMap := make(map[int]int)
skuIDMap := make(map[int]int)
for _, skuName := range skuNamesInfo.SkuNames {
storeIDMap[skuName.StoreID] = 1
for _, sku := range skuName.Skus {
skuIDMap[sku.SkuID] = 1
}
}
return jxutils.IntMap2List(storeIDMap), jxutils.IntMap2List(skuIDMap)
}
// 根据已经部分关注的商品,得到已经存在的门店商品单价
func updateUnitPrice4StoreSkuNameNew(db *dao.DaoDB, skuNamesInfo *dao.StoreSkuNamesInfo) (err error) {
storeIDMap := make(map[int]int)
skuNameIDMap := make(map[int]int)
for _, skuName := range skuNamesInfo.SkuNames {
storeIDMap[skuName.StoreID] = 1
skuNameIDMap[skuName.SkuName.ID] = 1
}
storeSkuNameInfo, err := dao.GetExistingStoreSkuNameInfo(db, jxutils.IntMap2List(storeIDMap), jxutils.IntMap2List(skuNameIDMap))
if err == nil {
infoMap := make(map[int64]*dao.StoreSkuNameInfo)
for _, v := range storeSkuNameInfo {
infoMap[jxutils.Combine2Int(v.StoreID, v.NameID)] = v
}
for _, skuName := range skuNamesInfo.SkuNames {
if tmpInfo := infoMap[jxutils.Combine2Int(skuName.StoreID, skuName.SkuName.ID)]; tmpInfo != nil {
skuName.UnitPrice = int(tmpInfo.UnitPrice)
}
}
}
return err
}
func updateSaleInfo4StoreSkuName(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs, skuIDs []int, params map[string]interface{}, skuNamesInfo *dao.StoreSkuNamesInfo, offset, pageSize int) (err error) {
var (
saleInfoList []*SkuSaleInfo
timeList []time.Time
fromCount, toCount int
)
saleInfoMap := make(map[int64]*SkuSaleInfo)
toTimeStr := ""
if params["stToTime"] != nil {
toTimeStr = params["stToTime"].(string)
}
if timeList, err = jxutils.BatchStr2Time(params["stFromTime"].(string), toTimeStr); err != nil {
return 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 {
return err
}
for _, saleInfo := range saleInfoList {
saleInfoMap[jxutils.Combine2Int(saleInfo.StoreID, saleInfo.SkuID)] = saleInfo
}
var newSkuNames []*dao.StoreSkuNameExt
for _, skuName := range skuNamesInfo.SkuNames {
var newSkus []*dao.StoreSkuExt
for _, sku := range skuName.Skus {
saleInfo := saleInfoMap[jxutils.Combine2Int(skuName.StoreID, sku.SkuID)]
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]
}
return err
}
func getValidStoreVendorMap(db *dao.DaoDB, storeIDs []int) (realVendorMap map[int]int, err error) {
storeMapList, err := dao.GetStoresMapList(db, nil, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "")
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 <= ?
`
if utils.IsTimeZero(toTime) {
toTime = time.Now()
}
sqlParams := []interface{}{
model.OrderStatusFinished,
fromTime,
toTime,
}
if len(storeIDs) > 0 {
sql += `
AND IF(t2.jx_store_id <> 0, jx_store_id, store_id) IN (` + dao.GenQuestionMarks(len(storeIDs)) + `)
`
sqlParams = append(sqlParams, 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)
if err = dao.GetRows(db, &saleInfoList, sql, sqlParams...); err == nil {
// globals.SugarLogger.Debug(utils.Format4Output(saleInfoList, false))
return saleInfoList, nil
}
return nil, err
}
func asyncStoreSkuOpFilter(ctx *jxcontext.Context, isAsync bool) bool {
if !isAsync {
authType := ctx.GetLoginInfo().GetAuthType()
if authType == weixin.AuthTypeMini || authType == weixin.AuthTypeMP {
userMobile, _ := ctx.GetMobileAndUserID()
isAsync = asyncOpMobileMap[userMobile] == 0
}
}
return isAsync
}
func UpdateStoreSku(ctx *jxcontext.Context, causeFlag, storeID int, skuBindInfo *StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
return UpdateStoreSkus(ctx, causeFlag, storeID, []*StoreSkuBindInfo{skuBindInfo}, isAsync, isContinueWhenError)
}
func UpdateStoreSkus(ctx *jxcontext.Context, causeFlag, storeID int, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
return UpdateStoresSkus(ctx, causeFlag, []int{storeID}, skuBindInfos, false, false, isAsync, isContinueWhenError)
}
func UpdateStoresSkus(ctx *jxcontext.Context, causeFlag int, storeIDs []int, skuBindInfos []*StoreSkuBindInfo, isScale, isRefreshHigh, isAsync, isContinueWhenError bool) (hint string, err error) {
globals.SugarLogger.Debugf("UpdateStoresSkus:%s, storeIDs:%v, skuBindInfos:%s", ctx.GetTrackInfo(), storeIDs, utils.Format4Output(skuBindInfos, true))
if beego.BConfig.RunMode == "jxgy" {
var num int64
db := dao.GetDB()
skuIDs, err := updateStoresSkusWithoutSync(ctx, db, storeIDs, skuBindInfos, isScale, isRefreshHigh)
if err != nil {
return "", err
}
isAsync = asyncStoreSkuOpFilter(ctx, isAsync)
num = int64(len(skuIDs))
if num > 0 {
hint, err = CurVendorSync.SyncStoresSkus(ctx, nil, causeFlag, db, nil, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
}
if num == 0 || !isAsync || hint == "" {
hint = utils.Int64ToStr(num)
}
} else {
flag, _ := doStoreSkuAudit(ctx, storeIDs, skuBindInfos)
if !flag {
var num int64
db := dao.GetDB()
skuIDs, err := updateStoresSkusWithoutSync(ctx, db, storeIDs, skuBindInfos, isScale, isRefreshHigh)
if err != nil {
return "", err
}
isAsync = asyncStoreSkuOpFilter(ctx, isAsync)
num = int64(len(skuIDs))
if num > 0 {
hint, err = CurVendorSync.SyncStoresSkus(ctx, nil, causeFlag, db, nil, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
}
if num == 0 || !isAsync || hint == "" {
hint = utils.Int64ToStr(num)
}
}
}
return hint, err
}
func UpdateStoresSkusWithoutSync(ctx *jxcontext.Context, storeIDs []int, skuBindInfos []*StoreSkuBindInfo, isRefreshHigh bool) (err error) {
db := dao.GetDB()
if len(storeIDs) == 0 {
stores, _ := dao.GetStoreList(db, nil, nil, nil, nil, nil, "")
for _, v := range stores {
storeIDs = append(storeIDs, v.ID)
}
}
updateStoresSkusWithoutSync(ctx, db, storeIDs, skuBindInfos, false, isRefreshHigh)
return err
}
func UpdateStoresSkusByBind(ctx *jxcontext.Context, parentTask tasksch.ITask, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError, isFos 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 > 0 {
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], false, false)
if err = err2; err != nil {
// dao.Rollback(db)
return "", err
}
for _, v := range skuIDs {
skuIDMap[v] = 1
}
num += int64(len(skuIDs))
}
// dao.Commit(db)
isAsync = asyncStoreSkuOpFilter(ctx, isAsync)
if num > 0 {
skuIDs := jxutils.IntMap2List(skuIDMap)
hint, err = CurVendorSync.SyncStoresSkus(ctx, parentTask, 0, db, nil, storeIDs, skuIDs, isFos, 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 []*tStoreNameBind
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)
upcMap := make(map[string]int)
for _, v := range skuBindInfos {
if v.NameID != 0 {
if nameIDMap[v.NameID] != 1 {
outSkuBindInfos = append(outSkuBindInfos, v)
nameIDMap[v.NameID] = 1
}
} else if v.UPC != "" {
if upcMap[v.UPC] != 1 {
outSkuBindInfos = append(outSkuBindInfos, v)
upcMap[v.UPC] = 1
}
}
}
return outSkuBindInfos
}
func updateStoresSkusWithoutSync(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs []int, skuBindInfos []*StoreSkuBindInfo, isScale, isRefreshHigh bool) (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
// }
globals.SugarLogger.Debugf("updateStoresSkusWithoutSync2, storeIDs:%v, skuBindInfos:%s", storeIDs, utils.Format4Output(skuBindInfos, false))
isUserCanDirectChangePrice := true
if user := ctx.GetFullUser(); user != nil {
isUserCanDirectChangePrice = user.Type&model.UserTypeOperator != 0
}
userName := ctx.GetUserName()
needSyncIDMap := make(map[int]int)
isSyncSkus := false
var appCodeList []string
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
for _, storeID := range storeIDs {
// todo 可以考虑在需要更新价格再获取
storeDetail, err := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDJX, "")
if err != nil || storeDetail == nil {
continue
}
if beego.BConfig.RunMode == "prod" || beego.BConfig.RunMode == "beta" {
if len(storeIDs) > 1 {
if storeDetail.StoreLevel == "D" || storeDetail.StoreLevel == "E" {
continue
}
}
}
scaleFactor := float64(1)
if isScale {
scaleFactor = 100 / float64(jxutils.ConstrainPayPercentage(storeDetail.PayPercentage))
}
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.status sku_status, t1.spec_quality, t1.spec_unit, t1.exd_sku_id,`
if needGetExistingUnitPrice {
sql += " IF(t5.unit_price > 0, t5.unit_price, t3.price) sku_name_price,"
}
sql += `
t3.unit sku_name_unit, t3.name, t3.status sku_name_status, t3.id name_id,
ts.change_price_type, ts.name store_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
`
if skuBindInfo.NameID != 0 {
sql += " AND t8.name_id = ?"
sqlParams = append(sqlParams, skuBindInfo.NameID)
} else if skuBindInfo.UPC != "" {
sql += " JOIN sku_name t9 ON t9.id = t8.name_id AND t9.upc = ?"
sqlParams = append(sqlParams, skuBindInfo.UPC)
}
sql += `
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, utils.DefaultTimeValue, storeID)
}
sql += " WHERE 1 = 1"
if skuBindInfo.NameID != 0 {
sql += " AND t1.name_id = ?"
sqlParams = append(sqlParams, skuBindInfo.NameID)
} else if skuBindInfo.UPC != "" {
sql += " AND t3.upc = ?"
sqlParams = append(sqlParams, skuBindInfo.UPC)
}
sql += ` AND t1.deleted_at = ?
FOR UPDATE`
sqlParams = append(sqlParams, 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
if isRefreshHigh {
if allBinds[0].UnitPrice <= unitPrice {
continue
}
}
} else {
unitPrice = allBinds[0].UnitPrice
if unitPrice == 0 {
unitPrice = allBinds[0].SkuNamePrice
}
}
unitPrice = int(float64(unitPrice) * scaleFactor)
for _, v := range allBinds {
var num int64
inSkuBind := inSkuBinsMap[v.RealSkuID]
isCanChangePrice := (isUserCanDirectChangePrice || jxutils.TranslateStorePriceType(v.ChangePriceType) != model.StoreChangePriceTypeBossDisabled)
var skuBind *model.StoreSkuBind
if v.ID == 0 {
// if v.ExdSkuID == "" {
if (strings.Contains(v.StoreName, model.ExdStoreName) && v.ExdSkuID != "") || (!strings.Contains(v.StoreName, model.ExdStoreName) && v.ExdSkuID == "") {
if skuBindInfo.IsFocus == 1 && v.SkuNameStatus == model.SkuStatusNormal && v.SkuStatus == model.SkuStatusNormal && isCanChangePrice {
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, // 缺省不可售?
}
skuBind.JxPrice = jxutils.CaculatePriceByPricePack(storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage), skuBind.Price)
if tmpStatus := getSkuSaleStatus(inSkuBind, skuBindInfo); tmpStatus != model.StoreSkuBindStatusNA {
skuBind.Status = tmpStatus
if inSkuBind != nil {
if inSkuBind.Stock != nil {
skuBind.Stock = *inSkuBind.Stock
} else {
if tmpStatus == model.StoreSkuBindStatusNormal {
skuBind.Stock = model.MaxStoreSkuStockQty
} else {
skuBind.Stock = 0
}
}
} else {
if tmpStatus == model.StoreSkuBindStatusNormal {
skuBind.Stock = model.MaxStoreSkuStockQty
} else {
skuBind.Stock = 0
}
}
}
if globals.IsAddEvent {
err = AddEventDetail(db, ctx, model.OperateAdd, v.RealSkuID, model.ThingTypeSku, storeID, "", utils.Int2Str(skuBind.UnitPrice))
}
setStoreSkuBindStatus(skuBind, model.SyncFlagNewMask)
dao.WrapAddIDCULDEntity(skuBind, userName)
if deletedSku := dao.GetDeletedStoreSkuBind(db, skuBind.StoreID, skuBind.SkuID); deletedSku == nil {
if err = dao.CreateEntity(db, skuBind); err != nil {
dao.Rollback(db)
return nil, err
}
num = 1
} else {
// 需要处理,在删除某个门店商品,同步失败的情况下,又把商品重新关注。
// 所以统一处理成恢复删除的记录,这样避免问题
skuBind.ID = deletedSku.ID
// vendorSkuID的赋值意义不大
skuBind.MtwmID = deletedSku.MtwmID
skuBind.EbaiID = deletedSku.EbaiID
if num, err = dao.UpdateEntity(db, skuBind); err != nil {
dao.Rollback(db)
return nil, err
}
}
//下面这段很难受
{
//可售了的才整
if skuBind.Status == model.StoreSkuBindStatusNormal {
//如果是京东关注,要去建商品
list1, _ := dao.GetStoresMapList(db, []int{model.VendorIDJD}, []int{storeID}, nil, model.StoreStatusAll, 1, "", "", "")
//表示这个门店绑定了京东
if len(list1) > 0 {
vendorOrgCodes, _ := dao.GetVendorOrgCode(db, model.VendorIDJD, list1[0].VendorOrgCode, model.VendorOrgTypePlatform)
//thingmap里肯定存在再判断有没有同步上去
thingMaps, _ := dao.GetThingMapList(db, model.ThingTypeSku, []int{model.VendorIDJD}, []int{v.RealSkuID}, []string{list1[0].VendorOrgCode})
if len(thingMaps) > 0 {
//如果平台ID为空未创建到京东
if thingMaps[0].VendorThingID == "" {
isSyncSkus = true
appCodeList = append(appCodeList, list1[0].VendorOrgCode)
//并且同步标志还没有带待创建因为addskuname现在建到thingmap上不会带待创建标志了
if !model.IsSyncStatusNew(thingMaps[0].SyncStatus) {
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.RealSkuID), model.ThingTypeSku, model.SyncFlagNewMask, false)
}
}
} else {
//万一不存在
isSyncSkus = true
appCodeList = append(appCodeList, list1[0].VendorOrgCode)
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.RealSkuID), model.ThingTypeSku, model.SyncFlagNewMask, false)
}
}
}
}
}
}
} else {
beforeMsg := *v
skuBind = &v.StoreSkuBind
if skuBindInfo.IsFocus == -1 && isCanChangePrice {
if globals.IsAddEvent {
err = AddEventDetail(db, ctx, model.OperateDelete, skuBind.SkuID, model.ThingTypeSku, storeID, "", "")
}
if globals.IsStoreSkuAct {
dao.DeleteEntity(db, &model.StoreSkuAct{
StoreID: skuBind.StoreID,
SkuID: skuBind.SkuID,
}, "StoreID", "SkuID")
}
if num, err = dao.DeleteEntityLogically(db, skuBind, map[string]interface{}{
model.FieldStatus: model.StoreSkuBindStatusDeleted,
model.FieldJdSyncStatus: model.SyncFlagDeletedMask,
model.FieldEbaiSyncStatus: model.SyncFlagDeletedMask,
model.FieldMtwmSyncStatus: model.SyncFlagDeletedMask,
model.FieldYbSyncStatus: model.SyncFlagDeletedMask,
model.FieldJdsSyncStatus: model.SyncFlagDeletedMask,
}, userName, nil); err != nil {
dao.Rollback(db)
return nil, err
}
//删除待审核商品信息
storeAudits, err := dao.GetStoreSkuAuditLight(db, []int{storeID}, []int{v.NameID}, model.StoreAuditStatusOnline)
if len(storeAudits) > 0 {
storeAudits[0].DeletedAt = time.Now()
if _, err = dao.UpdateEntity(db, storeAudits[0], "DeletedAt"); err != nil {
dao.Rollback(db)
return nil, err
}
}
} else {
// 用了SELECT FOR UPDATE后只更新修改字段是没有必要的暂时保留
updateFieldMap := make(map[string]interface{})
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 {
if tmpStatus != skuBind.Status {
updateFieldMap[model.FieldStatus] = 1
}
skuBind.Status = tmpStatus
setStoreSkuBindStatus(skuBind, model.SyncFlagSaleMask)
setStoreSkuBindStatus(skuBind, model.SyncFlagStockMask)
if tmpStatus == model.StoreSkuBindStatusNormal {
skuBind.Stock = model.MaxStoreSkuStockQty
//下面这段很难受
{
//如果是京东关注,要去建商品
list1, _ := dao.GetStoresMapList(db, []int{model.VendorIDJD}, []int{storeID}, nil, model.StoreStatusAll, 1, "", "", "")
//表示这个门店绑定了京东
if len(list1) > 0 {
vendorOrgCodes, _ := dao.GetVendorOrgCode(db, model.VendorIDJD, list1[0].VendorOrgCode, model.VendorOrgTypePlatform)
//thingmap里肯定存在再判断有没有同步上去
thingMaps, _ := dao.GetThingMapList(db, model.ThingTypeSku, []int{model.VendorIDJD}, []int{v.RealSkuID}, []string{list1[0].VendorOrgCode})
if len(thingMaps) > 0 {
//如果平台ID为空未创建到京东
if thingMaps[0].VendorThingID == "" {
isSyncSkus = true
appCodeList = append(appCodeList, list1[0].VendorOrgCode)
//并且同步标志还没有带待创建因为addskuname现在建到thingmap上不会带待创建标志了
if !model.IsSyncStatusNew(thingMaps[0].SyncStatus) {
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.RealSkuID), model.ThingTypeSku, model.SyncFlagNewMask, false)
}
}
} else {
//万一不存在
isSyncSkus = true
appCodeList = append(appCodeList, list1[0].VendorOrgCode)
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.RealSkuID), model.ThingTypeSku, model.SyncFlagNewMask, false)
}
}
}
} else {
skuBind.Stock = 0
}
}
if inSkuBind != nil {
if inSkuBind.Stock != nil {
updateFieldMap["Stock"] = 1
skuBind.Stock = *inSkuBind.Stock
setStoreSkuBindStatus(skuBind, model.SyncFlagStockMask)
}
}
if skuBindInfo.UnitPrice != 0 && isCanChangePrice { // 这里是否需要加此条件限制
price := jxutils.CaculateSkuPrice(unitPrice, v.SpecQuality, v.SpecUnit, v.SkuNameUnit)
jxPrice := jxutils.CaculatePriceByPricePack(storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage), price)
if unitPrice != skuBind.UnitPrice || price != skuBind.Price || jxPrice != skuBind.JxPrice {
if price != skuBind.Price {
setStoreSkuBindStatus(skuBind, model.SyncFlagPriceMask)
updateFieldMap["Price"] = 1
}
skuBind.UnitPrice = unitPrice
skuBind.Price = price
skuBind.JxPrice = jxPrice
updateFieldMap["UnitPrice"] = 1
updateFieldMap["JxPrice"] = 1
//TODO 2020-09-08 如果改价时商品在做直降,要取消这个商品的直降,再通过改价比例修改活动价,再上这个直降
// checkActDirectDown(ctx, skuBind, beforeMsg)
}
}
if skuBindInfo.StatusSaleBegin != 0 && skuBindInfo.StatusSaleEnd != 0 {
if err := ValidateStruct(skuBindInfo); err != nil {
globals.SugarLogger.Infof("更改商品:%s, 可售时间不合法!时间范围:[%v] 至 [%v]", allBinds[0].Name, skuBindInfo.StatusSaleBegin, skuBindInfo.StatusSaleEnd)
} else {
if skuBind.StatusSaleBegin != skuBindInfo.StatusSaleBegin || skuBind.StatusSaleEnd != skuBindInfo.StatusSaleEnd {
updateFieldMap["StatusSaleBegin"] = 1
updateFieldMap["StatusSaleEnd"] = 1
}
skuBind.StatusSaleBegin = skuBindInfo.StatusSaleBegin
skuBind.StatusSaleEnd = skuBindInfo.StatusSaleEnd
}
}
if skuBindInfo.StatusSaleBegin == 0 && skuBindInfo.StatusSaleEnd == 0 {
if skuBind.StatusSaleBegin != skuBindInfo.StatusSaleBegin || skuBind.StatusSaleEnd != skuBindInfo.StatusSaleEnd {
updateFieldMap["StatusSaleBegin"] = 1
updateFieldMap["StatusSaleEnd"] = 1
}
skuBind.StatusSaleBegin = skuBindInfo.StatusSaleBegin
skuBind.StatusSaleEnd = skuBindInfo.StatusSaleEnd
}
if globals.IsAddEvent {
if len(updateFieldMap) > 0 {
mapAfter := refutil.FindMapAndStructMixed(updateFieldMap, skuBind)
mapBefore := refutil.FindMapAndStructMixed(updateFieldMap, beforeMsg)
err = AddEventDetail(db, ctx, model.OperateUpdate, v.RealSkuID, model.ThingTypeSku, storeID, BuildDiffData(mapBefore), BuildDiffData(mapAfter))
}
}
if len(updateFieldMap) > 0 {
updateFieldMap[model.FieldJdSyncStatus] = 1
updateFieldMap[model.FieldEbaiSyncStatus] = 1
updateFieldMap[model.FieldMtwmSyncStatus] = 1
updateFieldMap[model.FieldUpdatedAt] = 1
updateFieldMap[model.FieldLastOperator] = 1
dao.WrapUpdateULEntity(skuBind, userName)
if skuBind.Status == model.SkuStatusNormal {
updateFieldMap["AutoSaleAt"] = 1
skuBind.AutoSaleAt = utils.DefaultTimeValue
}
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)
if isSyncSkus {
_, err = SyncSkus(ctx, nil, []int{model.VendorIDJD}, appCodeList, nil, skuIDs, true)
}
return skuIDs, err
}
// func checkActDirectDown(ctx *jxcontext.Context, skuBind *model.StoreSkuBind, beforeSkuBind tStoreSkuBindAndSpec) (err error) {
// var (
// originPrice = beforeSkuBind.Price
// price = skuBind.Price
// db = dao.GetDB()
// pageSize = 9999
// // percent = price / originPrice
// )
// if paged, _ := dao.QueryActs(db, 0, 0, pageSize, -1, "", -1, []int{model.ActStatusCreated}, []int{model.ActSkuDirectDown}, nil, skuBind.StoreID, []int{skuBind.SkuID}, 0, utils.ZeroTimeValue, utils.ZeroTimeValue, time.Now().AddDate(0, -2, 0), time.Now()); len(paged.Data) > 0 {
// for _, act := range paged.Data {
// if _, actStoreSkus, err := dao.GetActStoreSkuVendorList(db, act.ID, nil, []int{skuBind.StoreID}, []int{skuBind.SkuID}, "", 0, pageSize); err == nil && len(actStoreSkus) > 0 {
// var (
// handler = partner.GetPurchasePlatformFromVendorID(actStoreSkus[0].VendorID).(partner.IPurchasePlatformActHandler)
// actStoreSkuParam []*ActStoreSkuParam
// )
// for _, actStoreSku := range actStoreSkus {
// aa := &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: skuBind.StoreID,
// SkuID: actStoreSku.SkuID,
// ActID: act.ID,
// },
// }
// actStoreSkuParam = append(actStoreSkuParam, aa)
// }
// DeleteActStoreSkuBind(ctx, db, act.ID, actStoreSkuParam)
// actMap, err := dao.GetActVendorInfo(db, act.ID, []int{actStoreSkus[0].VendorID})
// if err != nil {
// return err
// }
// actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, act.ID, nil, nil, nil)
// if err != nil {
// return err
// }
// handler.SyncAct(ctx, nil, actMap[actStoreSkus[0].VendorID], nil, actStoreSkuMap[actStoreSkus[0].VendorID])
// }
// }
// }
// return err
// }
func getSkuSaleStatus(inSkuBind *StoreSkuBindSkuInfo, skuNameBindInfo *StoreSkuBindInfo) int {
tempSale := 0
if inSkuBind != nil {
tempSale = inSkuBind.IsSale
}
if tempSale == 0 {
tempSale = skuNameBindInfo.IsSale
}
if tempSale == -1 {
return model.StoreSkuBindStatusDontSale
} else if tempSale == 1 {
return model.StoreSkuBindStatusNormal
}
return model.StoreSkuBindStatusNA
}
func AddEventDetail(db *dao.DaoDB, ctx *jxcontext.Context, operateType, thingID, thingType, storeID int, beforeData, afterData string) (err error) {
if ctx.GetUserName() == "jxadmin" {
return err
}
operateEventDetail := &model.OperateEventDetail{
OperateType: operateType,
ThingID: thingID,
ThingType: thingType,
StoreID: storeID,
AccessUUID: ctx.GetTrackInfo()[0:strings.Index(ctx.GetTrackInfo(), ",")],
BeforeData: beforeData,
AfterData: afterData,
}
err = event.AddOperateEventDetail(db, operateEventDetail)
return err
}
func formatAutoSaleTime(autoSaleTime time.Time) (outAutoSaleTime time.Time) {
if utils.IsTimeZero(autoSaleTime) {
outAutoSaleTime = utils.DefaultTimeValue
} else {
outAutoSaleTime = jxutils.GetNextTimeFromList(time.Now(), []string{AutoSaleAtStr})
}
return outAutoSaleTime
}
// todo 应该用updateStoresSkusWithoutSync实现
func updateStoreSkusSaleWithoutSync(ctx *jxcontext.Context, storeID int, skuBindSkuInfos []*StoreSkuBindSkuInfo, autoSaleTime time.Time, ignoreDontSale bool, 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
}
autoSaleTime = formatAutoSaleTime(autoSaleTime)
for _, skuBind := range storeSkuList {
if v := skuBindSkuInfosMap[skuBind.SkuID]; v != nil && v.IsSale != 0 {
if !(!utils.IsTimeZero(autoSaleTime) && ignoreDontSale && skuBind.Status == model.StoreSkuBindStatusDontSale) {
statusResult := skuBind.Status
if v.IsSale == -1 || !utils.IsTimeZero(autoSaleTime) {
skuBind.Status = model.StoreSkuBindStatusDontSale
} else if v.IsSale == 1 {
skuBind.Status = model.StoreSkuBindStatusNormal
}
kvs := map[string]interface{}{
model.FieldLastOperator: ctx.GetUserName(),
model.FieldUpdatedAt: time.Now(),
model.FieldStatus: skuBind.Status,
model.FieldJdSyncStatus: skuBind.JdSyncStatus | model.SyncFlagSaleMask,
model.FieldEbaiSyncStatus: skuBind.EbaiSyncStatus | model.SyncFlagSaleMask,
model.FieldMtwmSyncStatus: skuBind.MtwmSyncStatus | model.SyncFlagSaleMask,
}
if utils.IsTimeZero(autoSaleTime) || skuBind.Status == model.SkuStatusNormal {
kvs["AutoSaleAt"] = utils.DefaultTimeValue
} else {
kvs["AutoSaleAt"] = autoSaleTime
}
if globals.IsAddEvent {
var status int
if v.IsSale == -1 {
status = model.StoreSkuBindStatusDontSale
} else {
status = model.StoreSkuBindStatusNormal
}
if status != statusResult {
mapAfter := make(map[string]interface{})
mapAfter["Status"] = status
mapBefore := make(map[string]interface{})
mapBefore["Status"] = statusResult
err = AddEventDetail(db, ctx, model.OperateUpdate, v.SkuID, model.ThingTypeSku, storeID, BuildDiffData(mapBefore), BuildDiffData(mapAfter))
}
}
if num, err = dao.UpdateEntityLogically(db, skuBind, kvs, 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 BuildDiffData(mapData map[string]interface{}) string {
dd := utils.MustMarshal(mapData)
result := utils.LimitUTF8StringLen(string(dd), 3200)
return result
}
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, autoSaleTime time.Time, ignoreDontSale bool, 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, autoSaleTime, ignoreDontSale, userName)
if err = err2; err != nil {
return "", err
}
num += int64(len(skuIDs))
}
isAsync = asyncStoreSkuOpFilter(ctx, isAsync)
if num > 0 {
skuIDs := make([]int, 0)
for _, v := range skuBindSkuInfos {
skuIDs = append(skuIDs, v.SkuID)
}
db := dao.GetDB()
hint, err = CurVendorSync.SyncStoresSkus(ctx, nil, 0, 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 int, toStoreIDs []int, copyMode string, isScale bool, params map[string]interface{}, userName string) (num int64, err error) {
if copyMode != CopyStoreSkuModeFresh && copyMode != CopyStoreSkuModeUpdate && copyMode != CopyStoreSkuModeUpdatePrice {
return 0, fmt.Errorf("不支持的拷贝模式:%s", copyMode)
}
//权限
if permission.IsRoled(ctx) {
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
if storeIDsMap[fromStoreID] == 0 {
return 0, fmt.Errorf("抱歉,您无权更改他人店铺商品 [%v]", fromStoreID)
}
for _, v := range toStoreIDs {
if storeIDsMap[v] == 0 {
return 0, fmt.Errorf("抱歉,您无权更改他人店铺商品 [%v]", v)
}
}
}
}
db := dao.GetDB()
fromStore, err := checkStoreExisting(db, fromStoreID)
if 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)
}
errList := errlist.New()
for _, toStoreID := range toStoreIDs {
toStore, err := checkStoreExisting(db, toStoreID)
if err != nil {
errList.AddErr(err)
break
}
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.jx_price = t1.jx_price * ? / 100,
t1.unit_price = t1.unit_price * ? / 100,
t1.jd_sync_status = t1.jd_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,
pricePercentage,
model.SyncFlagPriceMask,
model.SyncFlagPriceMask,
model.SyncFlagPriceMask,
toStoreID,
utils.DefaultTimeValue,
}
sql += sqlCatAndSku
sqlParams = append(sqlParams, sqlCatAndSkuParams)
num2, err2 := dao.ExecuteSQL(db, sql, sqlParams)
if err2 != nil {
errList.AddErr(err2)
} else {
num += num2
}
break
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if copyMode == CopyStoreSkuModeFresh {
// 将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.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,
toStoreID,
utils.DefaultTimeValue,
}
sqlDelete += sqlCatAndSku
sqlDeleteParams = append(sqlDeleteParams, sqlCatAndSkuParams)
// globals.SugarLogger.Debug(sqlDelete)
num2, err2 := dao.ExecuteSQL(db, sqlDelete, sqlDeleteParams)
if err = err2; err != nil {
errList.AddErr(err)
dao.Rollback(db)
break
}
num += num2
globals.SugarLogger.Debugf("CopyStoreSkus fromStoreID:%d, toStoreID:%d, trackInfo:%s num1:%d", fromStoreID, toStoreID, ctx.GetTrackInfo(), num2)
}
isModifyStatus := 1
syncStatus := model.SyncFlagStoreSkuOnlyMask
if copyMode == CopyStoreSkuModeUpdatePrice {
isModifyStatus = 0
syncStatus = model.SyncFlagPriceMask
}
scaleFactor := float64(1)
if isScale {
fromPayPercentage := jxutils.ConstrainPayPercentage(fromStore.PayPercentage)
toPayPercentage := jxutils.ConstrainPayPercentage(toStore.PayPercentage)
scaleFactor = float64(fromPayPercentage) / float64(toPayPercentage)
}
// 处理toStore中与fromStore中都存在的
sql := `
UPDATE store_sku_bind t1
JOIN store t11 ON t11.id = t1.store_id
LEFT JOIN store_sku_bind t0 ON t0.store_id = ? AND t0.sku_id = t1.sku_id AND t0.deleted_at = ?
JOIN store t01 ON t01.id = t0.store_id
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.jx_price = IF(t0.jx_price * ? / 100 > 0, t0.jx_price * ? / 100, 1) * ?,
t1.unit_price = IF(t0.unit_price * ? / 100 > 0, t0.unit_price * ? / 100, 1) * ?,
t1.status = IF(? = 0, t1.status, t0.status),
t1.jd_sync_status = t1.jd_sync_status | ?,
t1.mtwm_sync_status = t1.mtwm_sync_status | ?,
t1.ebai_sync_status = t1.ebai_sync_status | ?,
t1.stock = t0.stock
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,
scaleFactor,
pricePercentage,
pricePercentage,
scaleFactor,
pricePercentage,
pricePercentage,
scaleFactor,
isModifyStatus,
syncStatus,
syncStatus,
syncStatus,
toStoreID,
utils.DefaultTimeValue,
}
sql += sqlCatAndSku
sqlParams = append(sqlParams, sqlCatAndSkuParams)
// globals.SugarLogger.Debug(sql)
num2, err2 := dao.ExecuteSQL(db, sql, sqlParams)
globals.SugarLogger.Debugf("CopyStoreSkus fromStoreID:%d, toStoreID:%d, trackInfo:%s num2:%d", fromStoreID, toStoreID, ctx.GetTrackInfo(), num2)
if err = err2; err != nil {
errList.AddErr(err)
dao.Rollback(db)
break
}
num += num2
// 添加toStore中不存在但fromStore存在的
sql = `
INSERT INTO store_sku_bind(created_at, updated_at, last_operator, deleted_at, store_id, sku_id, sub_store_id, price, jx_price, unit_price, status,
jd_sync_status, ebai_sync_status, mtwm_sync_status, stock)
SELECT ?, ?, ?, ?, ?,
t1.sku_id, 0,
IF(t1.price * ? / 100 > 0, t1.price * ? / 100, 1) * ?,
IF(t1.jx_price * ? / 100 > 0, t1.jx_price * ? / 100, 1) * ?,
IF(t1.unit_price * ? / 100 > 0, t1.unit_price * ? / 100, 1) * ?,
IF(? = 0, ?, t1.status), ?, ?, ?, t1.stock
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,
scaleFactor,
pricePercentage,
pricePercentage,
scaleFactor,
pricePercentage,
pricePercentage,
scaleFactor,
isModifyStatus,
model.SkuStatusDontSale,
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)
num2, err = dao.ExecuteSQL(db, sql, sqlParams)
if err != nil {
errList.AddErr(err)
dao.Rollback(db)
break
}
num += num2
//上方insert会无视目标门店中未关注的商品以前关注后来取消关注所以这里批量删一下
sql2 := `
DELETE FROM store_sku_bind
WHERE store_id = ? AND sku_id IN (
SELECT b.sku_id FROM (
SELECT store_id,sku_id,count(*)
FROM store_sku_bind
WHERE store_id = ?
GROUP BY 1,2
HAVING count(*) > 1)b
)
AND deleted_at <> ?
`
sqlParams2 := []interface{}{
toStoreID, toStoreID, utils.DefaultTimeValue,
}
_, err = dao.ExecuteSQL(db, sql2, sqlParams2)
if err != nil {
errList.AddErr(err)
dao.Rollback(db)
break
}
globals.SugarLogger.Debugf("CopyStoreSkus fromStoreID:%d, toStoreID:%d, trackInfo:%s num3:%d", fromStoreID, toStoreID, ctx.GetTrackInfo(), num2)
dao.Commit(db)
//同一商品若源门店的规格少于要复制到的门店则在复制的门店里的其他规格的unitprice不会变
//导致复制的门店的商品unitprice不尽相同这里先处理一下
type tStore struct {
NameID int `orm:"column(name_id)"`
StoreID int `orm:"column(store_id)"`
}
var resultList []*tStore
sql3 := `
SELECT a.name_id, a.store_id FROM (
SELECT DISTINCT a.unit_price, b.name_id, a.store_id FROM store_sku_bind a, sku b, store c
WHERE a.sku_id = b.id
AND c.id = a.store_id
AND c.deleted_at = ?
AND a.store_id = ?
AND a.deleted_at = ?)a
GROUP BY 1, 2
HAVING COUNT(a.unit_price) > 1
`
sqlParams3 := []interface{}{utils.DefaultTimeValue, toStoreID, utils.DefaultTimeValue}
err = dao.GetRows(db, &resultList, sql3, sqlParams3)
if len(resultList) > 0 {
var skuBindInfos []*StoreSkuBindInfo
for _, v := range resultList {
storeSkus, _ := dao.GetStoreSkusByNameIDs(db, []int{v.StoreID}, v.NameID)
unitPirce := storeSkus[0].UnitPrice
skuBindInfo := &StoreSkuBindInfo{
StoreID: v.StoreID,
NameID: v.NameID,
UnitPrice: int(unitPirce),
}
skuBindInfos = append(skuBindInfos, skuBindInfo)
}
_, err = updateStoresSkusWithoutSync(ctx, db, []int{toStoreID}, skuBindInfos, false, false)
}
}
if globals.IsAddEvent {
mapAfter := make(map[string]interface{})
mapAfter["ToStoreIDs"] = toStoreIDs
mapAfter["CopyMode"] = copyMode
mapAfter["IsScale"] = isScale
mapAfter["PricePercentage"] = pricePercentage
mapBefore := make(map[string]interface{})
mapBefore["FromStoreID"] = fromStoreID
err = AddEventDetail(db, ctx, model.OperateCopyStoreSkus, 0, model.ThingTypeSku, fromStoreID, BuildDiffData(mapBefore), BuildDiffData(mapAfter))
}
return num, errList.GetErrListAsOne()
}
func shouldPendingStorePriceChange(ctx *jxcontext.Context, storeID int, skuBindInfo *StoreSkuBindInfo) (shouldPending bool, err error) {
if globals.EnablePendingChange {
if skuBindInfo.IsFocus != 1 && (ctx.GetLoginType() == weixin.AuthTypeMP || ctx.GetLoginType() == weixin.AuthTypeMini || ctx.GetUserName() == "fakeboss") {
db := dao.GetDB()
store := &model.Store{}
store.ID = storeID
if err = dao.GetEntity(db, store); err != nil {
return false, err
}
return jxutils.TranslateStorePriceType(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, 0, []int{op.StoreID}, []*StoreSkuBindInfo{skuBindInfo}, false, false, 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.EbaiSyncStatus |= status
skuBind.MtwmSyncStatus |= status
skuBind.YbSyncStatus |= status
skuBind.JdsSyncStatus |= status
}
func checkStoreExisting(db *dao.DaoDB, storeID int) (store *model.Store, err error) {
store = &model.Store{}
store.ID = storeID
if err = dao.GetEntity(db, store); err != nil {
if err == orm.ErrNoRows {
return nil, fmt.Errorf("门店:%d不存在", storeID)
}
return nil, err
}
return store, 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, []int{vendorID}, storeIDs, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "")
if err != nil {
return "", err
}
if len(storeMapList) != len(storeIDs) {
return "", fmt.Errorf("门店绑定信息不匹配,请确定门店绑定且只绑定了京东平台")
}
storeMap := make(map[int]*dao.StoreDetail)
for _, v := range storeMapList {
if v.VendorID != vendorID {
return "", fmt.Errorf("门店%d绑定的不是京东", v.StoreID)
}
storeMap[v.StoreID], err = dao.GetStoreDetail(db, v.StoreID, v.VendorID, "")
if err != nil {
return "", err
}
}
skuList, err := dao.GetSkusWithVendor(db, []int{vendorID}, nil, nil, nil, false)
if err != nil {
return "", err
}
skuNameMap := make(map[int]*model.SkuName)
skuMap := make(map[int]*dao.StoreSkuSyncInfo)
bareStoreSkuMap := make(map[string][]*partner.StoreSkuInfo)
for _, sku := range skuList {
if skuNameMap[sku.NameID] == nil {
skuNameMap[sku.NameID] = &model.SkuName{
Unit: sku.Unit,
}
}
skuMap[sku.ID] = sku
bareStoreSkuMap[sku.VendorOrgCode] = append(bareStoreSkuMap[sku.VendorOrgCode], &partner.StoreSkuInfo{
SkuID: sku.ID,
VendorSkuID: sku.VendorSkuID,
})
}
handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
var storeSkuList []*model.StoreSkuBind
rootTask := tasksch.NewParallelTask(fmt.Sprintf("根据厂家门店商品信息相应刷新本地数据:%v", storeIDs), tasksch.NewParallelConfig().SetParallelCount(1), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
oneStoreMap := batchItemList[0].(*model.StoreMap)
subTask := tasksch.NewSeqTask(fmt.Sprintf("根据厂家门店商品信息相应刷新本地数据:%s", model.VendorChineseNames[oneStoreMap.VendorID]), ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
bareStoreSkuList, err2 := handler.GetStoreSkusBareInfo(ctx, oneStoreMap.VendorOrgCode, task, oneStoreMap.StoreID, oneStoreMap.VendorStoreID, bareStoreSkuMap[oneStoreMap.VendorOrgCode])
// globals.SugarLogger.Debug(utils.Format4Output(bareStoreSkuList, false))
if err = err2; err == nil || len(bareStoreSkuList) > 0 {
err = nil // todo 如果部分失败,强制忽略错误
for _, v := range bareStoreSkuList {
storeSkuList = append(storeSkuList, &model.StoreSkuBind{
StoreID: oneStoreMap.StoreID,
SkuID: v.SkuID,
Status: v.Status,
Price: int(v.VendorPrice),
})
}
}
case 1:
if len(storeSkuList) > 0 {
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, priceAdd := jxutils.GetPricePercentageByVendorPrice(storeMap[v.StoreID].PricePercentagePackObj, v.Price, int(storeMap[v.StoreID].PricePercentage))
skuName := skuNameMap[skuMap[v.SkuID].NameID]
v.Price = jxutils.CaculateSkuPriceFromVendor(v.Price, pricePercentage, priceAdd)
v.UnitPrice = jxutils.CaculateSkuPriceFromVendor(skuName.Price, pricePercentage, priceAdd)
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.HandleTask(subTask, task, true).Run()
_, err = subTask.GetResult(0)
return retVal, err
}, storeMapList)
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.StoreSkuInfo, 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.StoreSkuInfo)
_, 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, _ := partner.GetPurchasePlatformFromVendorID(loopMapInfo.VendorID).(partner.IPurchasePlatformStoreSkuHandler); handler != nil {
storeSkuList, err2 := dao.GetStoreSkus2(db, loopMapInfo.VendorID, storeID, skuIDs, false)
if err = err2; err == nil && len(storeSkuList) > 0 {
bareStoreSkuInfoList := make([]*partner.StoreSkuInfo, len(skuIDs))
for k, v := range storeSkuList {
bareStoreSkuInfoList[k] = &partner.StoreSkuInfo{
SkuID: v.SkuID,
VendorSkuID: v.VendorSkuID,
}
}
outBareStoreSkuInfoList, err2 := handler.GetStoreSkusBareInfo(ctx, loopMapInfo.StoreMapList[0].VendorOrgCode, 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, loopMapInfo.StoreMapList[0].VendorOrgCode, 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
}
func AutoSaleStoreSku(ctx *jxcontext.Context, storeIDs []int, isNeedSync bool) (err error) {
db := dao.GetDB()
storeSkuList, err := dao.GetAutoSaleStoreSku(db, storeIDs)
if err != nil {
return err
}
storeSkuMap := make(map[int][]*model.StoreSkuBind)
for _, v := range storeSkuList {
storeSkuMap[v.StoreID] = append(storeSkuMap[v.StoreID], v)
}
now := time.Now()
for storeID, storeSkuList := range storeSkuMap {
var skuIDs []int
for _, storeSku := range storeSkuList {
if now.Sub(storeSku.AutoSaleAt) > 0 {
storeSku.AutoSaleAt = utils.DefaultTimeValue
if storeSku.Status != model.SkuStatusNormal {
storeSku.Status = model.SkuStatusNormal
skuIDs = append(skuIDs, storeSku.SkuID)
}
if _, err = dao.UpdateEntity(db, storeSku, "AutoSaleAt", model.FieldStatus); err != nil {
return err
}
}
}
if isNeedSync && len(skuIDs) > 0 {
if _, err = CurVendorSync.SyncStoresSkus(ctx, nil, model.SyncFlagSaleMask, db, nil, []int{storeID}, skuIDs, false, true, true); err != nil {
return err
}
}
}
return err
}
func ReCalculateJxPrice(db *dao.DaoDB, ctx *jxcontext.Context, storeIDs []int) (hint string, err error) {
task := tasksch.NewParallelTask("刷新京西平台价格", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeID := batchItemList[0].(int)
if storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDJX, ""); err == nil {
if storeSkuList, err := dao.GetStoresSkusInfo(db, []int{storeID}, nil); err == nil {
for _, skuBind := range storeSkuList {
skuBind.JxPrice = jxutils.CaculatePriceByPricePack(storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage), skuBind.Price)
dao.UpdateEntity(db, skuBind, "JxPrice")
}
} else {
return nil, err
}
} else {
return nil, err
}
return retVal, err
}, storeIDs)
tasksch.HandleTask(task, nil, true).Run()
hint = task.GetID()
return hint, err
}
func ReCalculateJxPriceLight(db *dao.DaoDB, ctx *jxcontext.Context, storeID int) (err error) {
if storeID != 0 {
if storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDJX, ""); err == nil {
if storeSkuList, err := dao.GetStoresSkusInfo(db, []int{storeID}, nil); err == nil {
for _, skuBind := range storeSkuList {
skuBind.JxPrice = jxutils.CaculatePriceByPricePack(storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage), skuBind.Price)
dao.UpdateEntity(db, skuBind)
}
} else {
return err
}
} else {
return err
}
}
return err
}
func GetTopSkusByStoreIDs(ctx *jxcontext.Context, storeIDs []int) (storeSkuNameExt2 []*dao.StoreSkuNameExt, err error) {
var (
db = dao.GetDB()
skuMap = make(map[int]*dao.StoreSkuNameExt)
)
if len(storeIDs) == 0 {
return storeSkuNameExt2, err
}
storeSkuNameExt, err := dao.GetTopSkusByStoreIDs(db, storeIDs)
if err != nil {
return nil, err
}
for _, v := range storeSkuNameExt {
if skuMap[v.SkuID] == nil {
skuMap[v.SkuID] = v
}
if skuMap[v.SkuID] != nil && v.Count != 0 {
skuMap[v.SkuID] = v
}
}
for _, v := range skuMap {
storeSkuNameExt2 = append(storeSkuNameExt2, v)
}
for i := 0; i < len(storeSkuNameExt2)-1; i++ {
for j := 0; j < len(storeSkuNameExt2)-i-1; j++ {
if storeSkuNameExt2[j].Count < storeSkuNameExt2[j+1].Count {
tmp := storeSkuNameExt2[j]
storeSkuNameExt2[j] = storeSkuNameExt2[j+1]
storeSkuNameExt2[j+1] = tmp
}
}
}
return storeSkuNameExt2, err
}
func GetTopSkusByCityCode(ctx *jxcontext.Context, cityCode, storeID int) (skuNameAndPlaceList []*dao.SkuNameAndPlace, err error) {
db := dao.GetDB()
orderCreate := time.Now().AddDate(0, -1, 0)
var skuNameAndPlace []*dao.SkuNameAndPlace
if cityCode > 0 {
skuNameAndPlace, err = dao.GetTopSkusByCityCode(db, cityCode, orderCreate)
} else {
skuNameAndPlace, err = dao.GetTopSkusByNoCityCode(db)
}
if storeID > 0 {
var skuNameList []*model.SkuName
//不可售的商品nameID列表
sql := `
SELECT DISTINCT b.name_id id
FROM store_sku_bind a
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
WHERE a.deleted_at = ?
AND a.store_id = ?
AND a.status <> ?
AND b.name_id NOT IN(SELECT DISTINCT b.name_id
FROM store_sku_bind a
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
WHERE a.deleted_at = ?
AND a.store_id = ?
AND a.status = ?)
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
utils.DefaultTimeValue,
storeID,
model.StoreSkuBindStatusNormal,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
storeID,
model.StoreSkuBindStatusNormal,
}
err = dao.GetRows(db, &skuNameList, sql, sqlParams...)
var skuNameMap = make(map[int]*model.SkuName)
for _, v := range skuNameList {
skuNameMap[v.ID] = v
}
store, err := dao.GetStoreDetail(db, storeID, -1, "")
if err != nil {
return nil, err
}
var payPercentage int
if store.PayPercentage < 50 {
payPercentage = 70
} else {
payPercentage = store.PayPercentage
}
for _, v := range skuNameAndPlace {
if skuNameMap[v.ID] != nil {
var skuList []*model.SkuAndName
storeSkuSyncInfo, _ := dao.GetStoreSkusAndSkuName(db, []int{storeID}, nil, []int{v.ID})
for _, storeSkuSync := range storeSkuSyncInfo {
sku, _ := dao.GetSkus(db, []int{storeSkuSync.ID}, nil, nil, nil, nil)
sku[0].Price = int(storeSkuSync.Price)
skuList = append(skuList, sku...)
}
v.UnitPrice = int(storeSkuSyncInfo[0].UnitPrice)
v.Skus = skuList
for _, vv := range skuList {
var (
storeSkuNameExt []*dao.StoreSkuNameExt
skusList []*dao.StoreSkuExt
)
vv.StoreSkuStatus = model.StoreSkuBindStatusDontSale
skus := &dao.StoreSkuExt{
SkuID: vv.ID,
BindPrice: vv.Price,
}
skusList = append(skusList, skus)
storeSkuName := &dao.StoreSkuNameExt{
Skus: skusList,
StoreID: storeID,
PayPercentage: payPercentage,
}
storeSkuNameExt = append(storeSkuNameExt, storeSkuName)
skuNamesInfo := &dao.StoreSkuNamesInfo{
SkuNames: storeSkuNameExt,
}
dao.UpdateActPrice4StoreSkuNameNew(db, []int{storeID}, []int{vv.ID}, skuNamesInfo, -1)
if skuNamesInfo.SkuNames[0].Skus[0] != nil {
vv.ActPrice = skuNamesInfo.SkuNames[0].Skus[0].ActPrice
vv.ActID = skuNamesInfo.SkuNames[0].Skus[0].ActID
vv.ActType = skuNamesInfo.SkuNames[0].Skus[0].ActType
vv.EarningPrice = skuNamesInfo.SkuNames[0].Skus[0].EarningPrice
vv.EarningActID = skuNamesInfo.SkuNames[0].Skus[0].EarningActID
}
}
skuNameAndPlaceList = append(skuNameAndPlaceList, v)
}
}
} else {
skuNameAndPlaceList = append(skuNameAndPlaceList, skuNameAndPlace...)
}
i := 1
for _, v := range skuNameAndPlaceList {
v.Sequence = i
i++
}
if len(skuNameAndPlaceList) <= 100 {
return skuNameAndPlaceList, err
} else {
return skuNameAndPlaceList[0:100], err
}
}
func GetTopCategoriesByStoreIDs(ctx *jxcontext.Context, storeIDs []int) (skuCategory []*model.SkuCategory, err error) {
var (
skuCategory2 []*model.SkuCategory
skuCategoryMap = make(map[int]*model.SkuCategory)
limit = 10
)
if len(storeIDs) == 0 {
return skuCategory, err
}
db := dao.GetDB()
skuCategory, err = dao.GetTopCategoriesByStoreIDs(db, storeIDs, limit)
//若大于等于10个就不用做下面的操作
if len(skuCategory) >= limit {
return skuCategory, err
}
if len(skuCategory) > 0 {
for _, v := range skuCategory {
skuCategoryMap[v.ID] = v
}
}
//推荐分类若不满10个则填满10个
if (len(skuCategory) < limit && len(skuCategory) > 0) || len(skuCategory) == 0 {
skuCategory2, err = dao.GetCategories(db, -1, 1, nil, false)
if len(skuCategory2) > 0 {
for _, v := range skuCategory2 {
if skuCategoryMap[v.ID] == nil {
if !strings.Contains(v.Name, "赠品") {
skuCategory = append(skuCategory, v)
}
}
if len(skuCategory) >= limit {
break
}
}
}
}
if err != nil {
return nil, err
}
return skuCategory, err
}
func RefershStoreSkusMidPrice(ctx *jxcontext.Context, storeIDs []int, isCountry bool) (err error) {
db := dao.GetDB()
if len(storeIDs) == 0 {
return err
}
for _, v := range storeIDs {
var skuBindInfos []*StoreSkuBindInfo
store, err := dao.GetStoreDetail(db, v, -1, "")
if err != nil {
return err
}
var payPercentage int
if store.PayPercentage < 50 {
payPercentage = 70
} else {
payPercentage = store.PayPercentage
}
storeSkuList, err := dao.GetStoresSkusInfo(db, []int{v}, nil)
for _, storeSku := range storeSkuList {
var priceReferList []*model.PriceReferSnapshot
if isCountry {
priceReferList, err = dao.GetPriceReferSnapshotNoPage(db, []int{0}, []int{storeSku.SkuID}, nil, utils.Time2Date(time.Now().AddDate(0, 0, -1)))
} else {
priceReferList, err = dao.GetPriceReferSnapshotNoPage(db, []int{store.CityCode}, []int{storeSku.SkuID}, nil, utils.Time2Date(time.Now().AddDate(0, 0, -1)))
}
if err != nil {
return err
}
if len(priceReferList) > 0 {
//TODO 高于中位价20%才刷, 2020-05-08
if priceReferList[0].MidUnitPrice >= 500 {
if storeSku.UnitPrice > priceReferList[0].MidUnitPrice/payPercentage*120 {
skuBindInfo := &StoreSkuBindInfo{
NameID: priceReferList[0].NameID,
UnitPrice: priceReferList[0].MidUnitPrice / payPercentage * 120,
}
skuBindInfos = append(skuBindInfos, skuBindInfo)
}
}
}
}
updateStoresSkusWithoutSync(ctx, db, []int{v}, skuBindInfos, false, false)
}
if err == nil {
CreateStorePriceScore(ctx)
}
return err
}
func RefreshJxPriceByExcel(ctx *jxcontext.Context, storeIDs []int, files []*multipart.FileHeader, isAsync, isContinueWhenError bool) (hint string, err error) {
if len(files) == 0 {
return "", errors.New("没有文件上传!")
}
if len(storeIDs) == 0 {
return "", errors.New("请选择至少一个门店!")
}
fileHeader := files[0]
file, err := fileHeader.Open()
hint, err = RefreshJxPriceByExcelBin(ctx, storeIDs, file, true, true)
file.Close()
return hint, err
}
func RefreshJxPriceByExcelBin(ctx *jxcontext.Context, storeIDs []int, reader io.Reader, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
storeSkuNamePriceList []*model.StoreSkuNamePrice
storeSkuNamePriceListUpdate []*model.StoreSkuNamePrice
skuBindInfosInter []interface{}
skuBindInfoList []*StoreSkuBindInfo
errMsg string
isErr bool = false
nameMap = make(map[string]string)
)
dataLock.dataFailedList = dataLock.dataFailedList[0:0]
dataLock.dataSuccessList = dataLock.dataSuccessList[0:0]
sheetParam := &SheetParam{
SkuNameIDCol: 5,
SkuPriceCol: 3,
SkuNameCol: 1,
SkuRow: 1,
SkuUnitCol: 2,
OutSkuIDCol: 0,
}
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
// xlsx, err := excelize.OpenFile("111.xlsx")
xlsx, err := excelize.OpenReader(reader)
if err != nil {
return "", err
}
rows, _ := xlsx.GetRows(xlsx.GetSheetName(1))
for rowNum, row := range rows {
if rowNum < sheetParam.SkuRow {
continue
}
storeSkuNamePrice := &model.StoreSkuNamePrice{}
errMsg += GetCellIntoStruct(rowNum, row, sheetParam, storeSkuNamePrice, nameMap)
storeSkuNamePriceList = append(storeSkuNamePriceList, storeSkuNamePrice)
}
if errMsg != "" {
return "", errors.New(errMsg)
} else {
isErr = true
}
case 1:
db := dao.GetDB()
storeSkuNamePriceListOrg, _ := dao.GetStoreSkuNamePrice(db)
CreateOrUpdateStoreSkuNamePriceByExcel(db, ctx, storeSkuNamePriceList, storeSkuNamePriceListOrg)
storeSkuNamePriceListNew, _ := dao.GetStoreSkuNamePrice(db)
storeSkuNamePriceMapNew := StoreSkuNamePriceList2Map(ctx, storeSkuNamePriceListNew)
for _, v := range storeSkuNamePriceList {
if storeSkuNamePriceMapNew[v.OutSkuID] != nil {
storeSkuNamePriceListUpdate = append(storeSkuNamePriceListUpdate, storeSkuNamePriceMapNew[v.OutSkuID])
}
}
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeSkuNamePrice := batchItemList[0].(*model.StoreSkuNamePrice)
var skuBindInfos []*StoreSkuBindInfo
nameIDGroup := strings.Split(storeSkuNamePrice.NameIDGroup, ",")
for _, v := range nameIDGroup {
if v != "" {
nameID := int(utils.Str2Int64(v))
for _, vv := range storeIDs {
skuList, err2 := dao.GetStoreSkusByNameIDs(db, []int{vv}, nameID)
err = err2
if len(skuList) > 0 {
unitPrice := 0
if skuList[0].Unit == model.UnitNames[0] {
if storeSkuNamePrice.Unit == "KG" {
unitPrice = storeSkuNamePrice.Price / 2
} else {
unitPrice = storeSkuNamePrice.Price
}
} else {
unitPrice = storeSkuNamePrice.Price
}
storeSkuBindInfo := &StoreSkuBindInfo{
NameID: nameID,
UnitPrice: unitPrice,
}
skuBindInfos = append(skuBindInfos, storeSkuBindInfo)
outSuccess := DataSuccess{
NameID: nameID,
Name: skuList[0].Name,
Unit: storeSkuNamePrice.Unit,
OrgPrice: utils.Str2Float64(utils.Int64ToStr(skuList[0].UnitPrice)) / 100,
NowPrice: utils.Str2Float64(utils.Int64ToStr(int64(unitPrice))) / 100,
MixPrice: utils.Str2Float64(utils.Int64ToStr(int64(unitPrice)-skuList[0].UnitPrice)) / 100,
}
dataLock.AppendDataSuccess(outSuccess)
} else {
//京西xx门店没有关注该商品
outFailed := DataFailed{
NameID: nameID,
Name: storeSkuNamePrice.Name,
Comment: fmt.Sprintf("京西[%v]门店没有关注该商品商品nameID[%v]Excel上商品名[%v]", vv, nameID, storeSkuNamePrice.Name),
}
dataLock.AppendDataFailed(outFailed)
}
}
} else {
//nameID为空还未填写nameID
outFailed := DataFailed{
NameID: 0,
Name: storeSkuNamePrice.Name,
Comment: fmt.Sprintf("商品nameID为空还未填写商品nameIDExcel上商品名[%v]", storeSkuNamePrice.Name),
}
dataLock.AppendDataFailed(outFailed)
}
}
retVal = skuBindInfos
return retVal, err
}
taskParallel := tasksch.NewParallelTask("刷新京西价", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, storeSkuNamePriceListUpdate)
tasksch.HandleTask(taskParallel, task, true).Run()
skuBindInfosInter, err = taskParallel.GetResult(0)
case 2:
//更新京西价
for _, v := range skuBindInfosInter {
skuBindInfoList = append(skuBindInfoList, v.(*StoreSkuBindInfo))
}
if isErr {
UpdateStoresSkus(ctx, 0, storeIDs, skuBindInfoList, false, false, isAsync, isContinueWhenError)
}
case 3:
//写Excel
WriteToExcelJx(task, dataLock.dataSuccessList, dataLock.dataFailedList)
}
return result, err
}
taskSeq := tasksch.NewSeqTask2("根据Excel刷新京西价", ctx, isContinueWhenError, taskSeqFunc, 4)
tasksch.HandleTask(taskSeq, nil, true).Run()
if !isAsync {
_, err = taskSeq.GetResult(0)
hint = "1"
} else {
hint = taskSeq.GetID()
}
return hint, err
}
func WriteToExcelJx(task *tasksch.SeqTask, dataSuccess []DataSuccess, dataFailed []DataFailed) (err error) {
var sheetList1 []*excel.Obj2ExcelSheetConfig
var sheetList2 []*excel.Obj2ExcelSheetConfig
var downloadURL1, downloadURL2, fileName1, fileName2 string
excelConf1 := &excel.Obj2ExcelSheetConfig{
Title: "sheet1",
Data: dataSuccess,
CaptionList: titleListSuccess,
}
sheetList1 = append(sheetList1, excelConf1)
excelConf2 := &excel.Obj2ExcelSheetConfig{
Title: "sheet1",
Data: dataFailed,
CaptionList: titleListFailed,
}
sheetList2 = append(sheetList2, excelConf2)
if excelConf1 != nil {
downloadURL1, fileName1, err = jxutils.UploadExeclAndPushMsg(sheetList1, "京西已更新商品")
} else {
baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess is nil!")
}
if excelConf2 != nil {
downloadURL2, fileName2, err = jxutils.UploadExeclAndPushMsg(sheetList2, "未更新商品")
} else {
baseapi.SugarLogger.Debug("WriteToExcel: dataFailed is nil!")
}
if err != nil {
baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName1, fileName2, err)
} else {
noticeMsg := fmt.Sprintf("[详情点我]path1=%s, path2=%s \n", downloadURL1, downloadURL2)
task.SetNoticeMsg(noticeMsg)
baseapi.SugarLogger.Debugf("WriteToExcel:upload %s ,%s success, downloadURL1:%s ,downloadURL2:%s", fileName1, fileName2, downloadURL1, downloadURL2)
}
return err
}
func CreateOrUpdateStoreSkuNamePriceByExcel(db *dao.DaoDB, ctx *jxcontext.Context, storeSkuNamePriceList []*model.StoreSkuNamePrice, storeSkuNamePriceListOrg []*model.StoreSkuNamePrice) (err error) {
storeSkuNamePriceMap := StoreSkuNamePriceList2Map(ctx, storeSkuNamePriceListOrg)
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
for _, v := range storeSkuNamePriceList {
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
if storeSkuNamePriceMap[v.OutSkuID] != nil {
v.ID = storeSkuNamePriceMap[v.OutSkuID].ID
v.UpdatedAt = time.Now()
dao.UpdateEntity(db, v)
} else {
dao.CreateEntity(db, v)
}
}
dao.Commit(db)
return err
}
func StoreSkuNamePriceList2Map(ctx *jxcontext.Context, storeSkuNamePriceList []*model.StoreSkuNamePrice) (result map[string]*model.StoreSkuNamePrice) {
result = make(map[string]*model.StoreSkuNamePrice, len(storeSkuNamePriceList))
for _, v := range storeSkuNamePriceList {
result[v.OutSkuID] = v
}
return result
}
func GetCellIntoStruct(rowNum int, row []string, sheetParam *SheetParam, storeSkuNamePrice *model.StoreSkuNamePrice, nameMap map[string]string) (errMsg string) {
for k, cell := range row {
if k == sheetParam.OutSkuIDCol {
if IsChineseChar(cell) {
return fmt.Sprintf("Excel格式排版发生了变化在[%v]列,[%v]行附近可能增加或减少了一列", k+1, rowNum+1)
}
storeSkuNamePrice.OutSkuID = cell
}
if k == sheetParam.SkuNameCol {
storeSkuNamePrice.Name = cell
}
if k == sheetParam.SkuNameIDCol {
cellReplace := strings.ReplaceAll(cell, "", ",")
if cellReplace != "" {
if cellReplace[len(cellReplace)-1:len(cellReplace)] == "," {
cellReplace = cellReplace[0 : len(cellReplace)-1]
}
nameIDs := strings.Split(cellReplace, ",")
for _, v := range nameIDs {
if nameMap[v] != "" {
return fmt.Sprintf(" Excel中含有重复的nameID[%v]列,[%v]行nameID [%v]\n", k+1, rowNum+1, v)
} else {
nameMap[v] = v
}
}
}
storeSkuNamePrice.NameIDGroup = cellReplace
}
if k == sheetParam.SkuPriceCol {
if IsChineseChar(cell) {
return fmt.Sprintf("Excel格式排版发生了变化在[%v]列,[%v]行附近可能增加或减少了一列", k+1, rowNum+1)
}
storeSkuNamePrice.Price = int(utils.Float64TwoInt64(utils.Str2Float64(cell) * 100))
}
if k == sheetParam.SkuUnitCol {
storeSkuNamePrice.Unit = cell
}
}
return errMsg
}
func (d *DataLock) AppendDataSuccess(dataSuccess DataSuccess) {
d.locker.Lock()
defer d.locker.Unlock()
d.dataSuccessList = append(d.dataSuccessList, dataSuccess)
}
func (d *DataLock) AppendDataFailed(dataFailed DataFailed) {
d.locker.Lock()
defer d.locker.Unlock()
d.dataFailedList = append(d.dataFailedList, dataFailed)
}
func IsChineseChar(str string) bool {
for _, r := range str {
if unicode.Is(unicode.Scripts["Han"], r) {
return true
}
}
return false
}
func GetStoreCategories(ctx *jxcontext.Context, storeID, parentID int) (catList []*model.SkuCategory, err error) {
return dao.GetStoreSkuCategories(dao.GetDB(), storeID, parentID)
}
func GetVendorStoreSkuPrice(ctx *jxcontext.Context, vendorIDs []int, skuID int, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
storeSkuListJD []DataVendorStoreSkuPrice
storeSkuListMT []DataVendorStoreSkuPrice
storeSkuListEB []DataVendorStoreSkuPrice
excelParamList []ExcelParam
)
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
for _, v := range vendorIDs {
vendorID := v
handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
handlerStore := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreHandler)
for _, v := range apimanager.CurAPIManager.GetAppOrgCodeList(vendorID) {
vendorStoreIDs, err2 := handlerStore.GetAllStoresVendorID(ctx, v)
err = err2
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorStoreID := batchItemList[0].(string)
var (
inStoreSkuList []*partner.StoreSkuInfo
storeDetail *dao.StoreDetail
inStoreSku = &partner.StoreSkuInfo{}
outStoreSkuList []*partner.StoreSkuInfo
)
db := dao.GetDB()
skuList, err := dao.GetSkusWithVendor(db, []int{vendorID}, []string{v}, nil, []int{skuID}, false)
if err != nil {
return retVal, err
}
if partner.IsMultiStore(vendorID) {
multiHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
storeDetail, err = multiHandler.ReadStore(ctx, v, vendorStoreID)
if len(skuList) > 0 {
inStoreSku.VendorSkuID = skuList[0].VendorSkuID
}
} else {
singleHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreHandler)
storeDetail, err = singleHandler.ReadStore(ctx, v, vendorStoreID)
inStoreSku.SkuID = skuID
}
inStoreSkuList = append(inStoreSkuList, inStoreSku)
storeDetail2, err := dao.GetStoreDetailByVendorStoreID(db, vendorStoreID, vendorID, "")
if storeDetail2 != nil {
outStoreSkuList, err = handler.GetStoreSkusBareInfo(ctx, v, task, storeDetail2.ID, vendorStoreID, inStoreSkuList)
} else {
outStoreSkuList, err = handler.GetStoreSkusBareInfo(ctx, v, task, 0, vendorStoreID, inStoreSkuList)
}
if storeDetail != nil {
if len(outStoreSkuList) == 0 {
data := DataVendorStoreSkuPrice{
StoreID: vendorStoreID,
StoreName: storeDetail.Name,
SkuID: skuID,
SkuName: skuList[0].Name,
VendorPrice: "",
}
retVal = []DataVendorStoreSkuPrice{data}
} else {
data := DataVendorStoreSkuPrice{
StoreID: vendorStoreID,
StoreName: storeDetail.Name,
SkuID: skuID,
SkuName: skuList[0].Name,
VendorPrice: utils.Float64ToStr(utils.Str2Float64(utils.Int64ToStr(outStoreSkuList[0].VendorPrice)) / 100),
}
retVal = []DataVendorStoreSkuPrice{data}
}
}
return retVal, err
}
taskParallel := tasksch.NewParallelTask("获取各平台所有门店某商品价格", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, vendorStoreIDs)
tasksch.HandleTask(taskParallel, task, true).Run()
storeSkuList, _ := taskParallel.GetResult(0)
for _, v := range storeSkuList {
if vendorID == model.VendorIDJD {
storeSkuListJD = append(storeSkuListJD, v.(DataVendorStoreSkuPrice))
}
if vendorID == model.VendorIDEBAI {
storeSkuListEB = append(storeSkuListEB, v.(DataVendorStoreSkuPrice))
}
if vendorID == model.VendorIDMTWM {
storeSkuListMT = append(storeSkuListMT, v.(DataVendorStoreSkuPrice))
}
}
}
}
excelParam1 := ExcelParam{
DataList: storeSkuListJD,
TitleList: titleListVendorStoreSkuPrice,
SheetName: "京东平台",
}
excelParam2 := ExcelParam{
DataList: storeSkuListEB,
TitleList: titleListVendorStoreSkuPrice,
SheetName: "饿百平台",
}
excelParam3 := ExcelParam{
DataList: storeSkuListMT,
TitleList: titleListVendorStoreSkuPrice,
SheetName: "美团平台",
}
excelParamList = append(excelParamList, excelParam1, excelParam2, excelParam3)
case 1:
WriteToExcelNormal(task, "各平台"+utils.Int2Str(skuID)+"商品所有门店价格", excelParamList)
}
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 WriteToExcelNormal(task *tasksch.SeqTask, fileName string, excelParam []ExcelParam) (err error) {
var sheetList []*excel.Obj2ExcelSheetConfig
for _, v := range excelParam {
if v.DataList != nil {
excelConf := &excel.Obj2ExcelSheetConfig{
Title: v.SheetName,
Data: v.DataList,
CaptionList: v.TitleList,
}
sheetList = append(sheetList, excelConf)
}
}
downloadURL, fileNameResult, err := jxutils.UploadExeclAndPushMsg(sheetList, fileName)
if err != nil {
baseapi.SugarLogger.Errorf("WriteToExcel:upload %s failed error:%v", fileNameResult, err)
} else {
noticeMsg := fmt.Sprintf("[详情点我]path=%s \n", downloadURL)
task.SetNoticeMsg(noticeMsg)
baseapi.SugarLogger.Debugf("WriteToExcel:upload %s success, downloadURL:%s", fileNameResult, downloadURL)
}
return err
}
func FocusStoreSkusByExcel(ctx *jxcontext.Context, files []*multipart.FileHeader, isAsync, isContinueWhenError bool) (hint string, err error) {
if len(files) == 0 {
return "", errors.New("没有文件上传!")
}
fileHeader := files[0]
file, err := fileHeader.Open()
hint, err = FocusStoreSkusByExcelBin(ctx, file, isAsync, isContinueWhenError)
file.Close()
return hint, err
}
func FocusStoreSkusByExcelBin(ctx *jxcontext.Context, reader io.Reader, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
skuMap = make(map[int]int)
db = dao.GetDB()
skuIDs []int
result1 []interface{}
)
sheetParam := &SheetParam{
OutSkuIDCol: 1,
SkuPriceCol: 3,
SkuRow: 1,
}
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
// xlsx, err := excelize.OpenFile("111.xlsx")
xlsx, err := excelize.OpenReader(reader)
if err != nil {
return result, err
}
rows, _ := xlsx.GetRows(xlsx.GetSheetName(1))
for rowNum, row := range rows {
if rowNum < sheetParam.SkuRow {
continue
}
GetCellForFocusStoreSkus(db, rowNum, row, sheetParam, skuMap)
}
case 1:
for k, _ := range skuMap {
skuIDs = append(skuIDs, k)
}
skuList, err := dao.GetSkus(db, skuIDs, nil, nil, nil, nil)
storeList, err := dao.GetStoreList(db, nil, nil, nil, nil, nil, "")
if err != nil && len(skuList) == 0 {
return result, err
}
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
store := batchItemList[0].(*model.Store)
var (
skuNameMap = make(map[int]int)
skuInfoMap = make(map[int][]*StoreSkuBindSkuInfo)
)
for _, v := range skuList {
var (
price int
specQuality float64
)
focusList, _ := dao.GetStoreSkuBindByNameID(db, store.ID, v.NameID, model.StoreSkuBindStatusNormal)
//有关注过
if len(focusList) > 0 {
price = focusList[0].UnitPrice
skuInfoMap[v.NameID] = append(skuInfoMap[v.NameID], &StoreSkuBindSkuInfo{
SkuID: v.ID,
IsSale: 1,
})
skuNameMap[v.NameID] = price
} else {
if v.Unit == model.SpecialUnit {
if v.SpecUnit == model.SpecUnitNames[1] || v.SpecUnit == model.SpecUnitNames[2] {
specQuality = float64(v.SpecQuality) * 1000
} else {
specQuality = float64(v.SpecQuality)
}
price = int(utils.Float64TwoInt64(utils.Int2Float64(model.SpecialSpecQuality) / specQuality * utils.Int2Float64(skuMap[v.ID])))
} else {
price = skuMap[v.ID]
}
if skuNameMap[v.NameID] < price {
skuNameMap[v.NameID] = price
}
}
}
var storeSkuBindInfo []*StoreSkuBindInfo
for k, v := range skuNameMap {
skuBindInfo := &StoreSkuBindInfo{
StoreID: store.ID,
NameID: k,
UnitPrice: v,
IsFocus: 1,
IsSale: 1,
Skus: skuInfoMap[k],
}
storeSkuBindInfo = append(storeSkuBindInfo, skuBindInfo)
}
retVal = storeSkuBindInfo
return retVal, err
}
taskParallel := tasksch.NewParallelTask("根据skuID关注商品", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, storeList)
tasksch.HandleTask(taskParallel, task, true).Run()
result1, _ = taskParallel.GetResult(0)
case 2:
var skuBindInfos []*StoreSkuBindInfo
for _, v := range result1 {
skuBindInfos = append(skuBindInfos, v.(*StoreSkuBindInfo))
}
UpdateStoresSkusByBind(ctx, task, skuBindInfos, true, true, false)
}
return result, err
}
taskSeq := tasksch.NewSeqTask2("根据Excel中skuID批量关注商品", ctx, isContinueWhenError, taskSeqFunc, 3)
tasksch.HandleTask(taskSeq, nil, true).Run()
if !isAsync {
_, err = taskSeq.GetResult(0)
hint = "1"
} else {
hint = taskSeq.GetID()
}
return hint, err
}
func GetCellForFocusStoreSkus(db *dao.DaoDB, rowNum int, row []string, sheetParam *SheetParam, skuMap map[int]int) {
var (
skuID int
price int
)
for k, cell := range row {
if k == sheetParam.OutSkuIDCol {
skuID = int(utils.Str2Int64(cell))
}
if k == sheetParam.SkuPriceCol {
price = int(utils.Float64TwoInt64(utils.Str2Float64(cell) * 100))
}
}
skuMap[skuID] = price
}
func FocusStoreSkusBySku(ctx *jxcontext.Context, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
var result1 []interface{}
db := dao.GetDB()
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) {
var (
price int
payPercentage int
)
skuBindInfo := batchItemList[0].(*StoreSkuBindInfo)
storeID := skuBindInfo.StoreID
skuID := skuBindInfo.Skus[0].SkuID
store, err := dao.GetStoreDetail(db, storeID, -1, "")
if len(skuBindInfos) > 1 {
if store.StoreLevel == "D" || store.StoreLevel == "E" {
return retVal, err
}
}
if err != nil {
return retVal, err
}
skuList, err := dao.GetSkus(db, []int{skuID}, nil, nil, nil, nil)
if err != nil {
return retVal, err
}
if len(skuList) == 0 {
return retVal, fmt.Errorf("未查询到此商品商品id [%d]", skuID)
}
focusList, _ := dao.GetStoreSkuBindByNameID(db, storeID, skuList[0].NameID, model.StoreSkuBindStatusNormal)
//有关注过
if len(focusList) > 0 {
price = focusList[0].UnitPrice
} else {
if store.PayPercentage < 50 {
payPercentage = 70
} else {
payPercentage = store.PayPercentage
}
priceReferList, _ := dao.GetPriceReferSnapshotNoPage(db, []int{0}, nil, []int{skuList[0].NameID}, utils.Time2Date(time.Now().AddDate(0, 0, -1)))
if len(priceReferList) > 0 {
if payPercentage == 100 {
price = priceReferList[0].MidUnitPrice * payPercentage / 100
} else {
price = priceReferList[0].MidUnitPrice / payPercentage * 100
}
}
}
skuBindSkuInfo := &StoreSkuBindSkuInfo{
SkuID: skuID,
IsSale: 1,
}
var skuBindSkuInfos []*StoreSkuBindSkuInfo
skuBindSkuInfos = append(skuBindSkuInfos, skuBindSkuInfo)
skuBindInfo2 := &StoreSkuBindInfo{
StoreID: storeID,
NameID: skuList[0].NameID,
UnitPrice: price,
IsFocus: 1,
Skus: skuBindSkuInfos,
}
retVal = []*StoreSkuBindInfo{skuBindInfo2}
return retVal, err
}
taskParallel := tasksch.NewParallelTask("根据skuID部分关注商品", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, skuBindInfos)
tasksch.HandleTask(taskParallel, task, true).Run()
result1, _ = taskParallel.GetResult(0)
case 1:
var skuBindInfos []*StoreSkuBindInfo
for _, v := range result1 {
skuBindInfos = append(skuBindInfos, v.(*StoreSkuBindInfo))
}
hint, err = UpdateStoresSkusByBind(ctx, task, skuBindInfos, isAsync, isContinueWhenError, true)
}
return result, err
}
taskSeq := tasksch.NewSeqTask2("根据skuID批量部分关注商品", 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 AutoFocusStoreSkusForTopSkus(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
db := dao.GetDB()
var (
result1 []interface{}
)
storeList, err := dao.GetStoreList(db, nil, nil, nil, []int{1}, nil, "")
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].(*model.Store)
var (
skuName []*model.SkuName
skuNameMap = make(map[int]int)
)
//物料店不自动关注畅销品
if autoNotFoucsStoreMap[v.ID] != 0 {
return retVal, err
}
sql := `
SELECT DISTINCT a.name_id id
FROM sku a
LEFT JOIN (SELECT DISTINCT b.name_id
FROM store_sku_bind a
JOIN sku b ON a.sku_id = b.id
WHERE a.deleted_at = ?
AND store_id = ?)b ON a.name_id = b.name_id
WHERE a.status = ?
AND a.deleted_at = ?
AND b.name_id IS NULL
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
v.ID,
model.SkuStatusNormal,
utils.DefaultTimeValue,
}
err = dao.GetRows(db, &skuName, sql, sqlParams...)
for _, name := range skuName {
skuNameMap[name.ID] = name.ID
}
skuNameAndPlaceList, err2 := GetTopSkusByCityCode(ctx, 0, 0)
//skuNameAndPlaceList, err2 := GetTopSkusByCityCode(ctx, v.CityCode, 0)
if err2 != nil {
return retVal, err2
}
var payPercentage int
if v.PayPercentage < 50 {
payPercentage = 70
} else {
payPercentage = v.PayPercentage
}
if len(skuNameAndPlaceList) > 0 {
var skuBindInfoList []*StoreSkuBindInfo
for _, vv := range skuNameAndPlaceList {
if skuNameMap[vv.ID] != 0 {
globals.SugarLogger.Debugf("testAutoFocusStoreSkusForTopSkus,storeID:%v,nameID:%v", v.ID, vv.ID)
storeSkuBindInfo := &StoreSkuBindInfo{
StoreID: v.ID,
NameID: vv.ID,
// UnitPrice: priceReferList[0].MidUnitPrice * payPercentage / 100,
IsFocus: 1,
IsSale: 0,
}
priceReferList, err := dao.GetPriceReferSnapshotNoPage(db, []int{vv.CityCode}, nil, []int{vv.ID}, utils.Time2Date(time.Now().AddDate(0, 0, -1)))
if err == nil && len(priceReferList) > 0 {
storeSkuBindInfo.UnitPrice = priceReferList[0].MidUnitPrice / payPercentage * 100
}
skuBindInfoList = append(skuBindInfoList, storeSkuBindInfo)
}
}
retVal = skuBindInfoList
}
return retVal, err
}
taskParallel := tasksch.NewParallelTask("自动关注畅销品-设置数据", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, storeList)
tasksch.HandleTask(taskParallel, task, true).Run()
result1, _ = taskParallel.GetResult(0)
case 1:
var skuBindInfos []*StoreSkuBindInfo
for _, v := range result1 {
skuBindInfos = append(skuBindInfos, v.(*StoreSkuBindInfo))
}
hint, err = UpdateStoresSkusByBind(ctx, nil, skuBindInfos, isAsync, isContinueWhenError, false)
}
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 AutoFocusStoreSkusWithoutFocus(ctx *jxcontext.Context, skuIDs []int, isSync bool) (err error) {
var (
nameMap = make(map[int]*StoreSkuBindInfo)
)
db := dao.GetDB()
storeList, err := dao.GetStoreList(db, nil, nil, nil, nil, nil, "")
for _, v := range storeList {
storeSkuList, _ := dao.GetStoreSkusAndSkuName(db, []int{v.ID}, skuIDs, nil)
for _, vv := range storeSkuList {
if nameMap[vv.ID] != nil {
nameMap[vv.ID].Skus = append(nameMap[vv.ID].Skus, &StoreSkuBindSkuInfo{
SkuID: vv.SkuID,
})
} else {
skuBindInfo := &StoreSkuBindInfo{
UnitPrice: int(vv.UnitPrice),
NameID: vv.NameID,
StoreID: v.ID,
Skus: []*StoreSkuBindSkuInfo{},
}
nameMap[vv.ID] = skuBindInfo
}
}
}
for _, v := range nameMap {
var skuBindInfoList []*StoreSkuBindInfo
skuBindInfoResult := &StoreSkuBindInfo{
NameID: v.NameID,
UnitPrice: v.UnitPrice,
IsFocus: 1,
}
var skuBindSkuList []*StoreSkuBindSkuInfo
skuMap := make(map[int]int)
skuList, _ := dao.GetSkus(db, nil, []int{v.NameID}, nil, nil, nil)
if len(v.Skus) != len(skuList) {
for _, skus := range v.Skus {
skuMap[skus.SkuID] = 1
}
for _, vv := range skuList {
if skuMap[vv.ID] != 1 {
continue
}
skuBindSkuList = append(skuBindSkuList, &StoreSkuBindSkuInfo{
SkuID: vv.ID,
IsSale: 0,
})
}
}
skuBindInfoList = append(skuBindInfoList, skuBindInfoResult)
if isSync {
UpdateStoreSkus(ctx, 0, v.StoreID, skuBindInfoList, true, true)
} else {
updateStoresSkusWithoutSync(ctx, db, []int{v.StoreID}, skuBindInfoList, false, false)
}
}
return err
}
func UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorIDs []int, files []*multipart.FileHeader, isAsync, isContinueWhenError bool) (hint string, err error) {
if len(files) == 0 {
return "", errors.New("没有文件上传!")
}
fileHeader := files[0]
file, err := fileHeader.Open()
hint, err = UpdateStoreSkusSpecTagBin(ctx, file, vendorIDs, isAsync, isContinueWhenError)
file.Close()
return hint, err
}
func UpdateStoreSkusSpecTagBin(ctx *jxcontext.Context, reader io.Reader, vendorIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
db = dao.GetDB()
results []*tUpdateSkuSpecTag
)
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
// xlsx, err := excelize.OpenFile("111.xlsx")
xlsx, err := excelize.OpenReader(reader)
if err != nil {
return result, err
}
rows, _ := xlsx.GetRows(xlsx.GetSheetName(1))
for rowNum, row := range rows {
if rowNum < 1 {
continue
}
var (
skuMap = &tUpdateSkuSpecTag{}
storeID int
skuID int
isSpec int
)
for k, cell := range row {
if cell != "" {
if k == 0 {
storeID = int(utils.Str2Int64(cell))
}
if k == 1 {
skuID = int(utils.Str2Int64(cell))
}
if k == 2 {
isSpec = int(utils.Str2Int64(cell))
}
}
}
skuMap.SkuID = skuID
skuMap.IsSpec = isSpec
skuMap.StoreID = storeID
results = append(results, skuMap)
}
case 1:
for i := 0; i < len(results)/2; i++ {
tmp := results[i]
results[i] = results[len(results)-i-1]
results[len(results)-i-1] = tmp
}
//权限
if permission.IsRoled(ctx) {
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
for _, v := range results {
if storeIDsMap[v.StoreID] == 0 {
continue
}
store, err := dao.GetStoreDetail(db, v.StoreID, model.VendorIDMTWM, "")
if err != nil || store == nil {
continue
}
mtapi := apimanager.CurAPIManager.GetAPI(model.VendorIDMTWM, store.VendorOrgCode).(*mtwmapi.API)
food, err := mtapi.RetailGet(store.VendorStoreID, utils.Int2Str(v.SkuID))
if err != nil || food == nil {
continue
}
var foodData = make(map[string]interface{})
if v.IsSpec != 0 && v.IsSpec == -1 {
v.IsSpec = 0
}
foodData["is_specialty"] = v.IsSpec
foodData["price"] = food.Price
if globals.EnableMtwmStoreWrite {
err = mtapi.RetailInitData(ctx.GetTrackInfo(), store.VendorStoreID, utils.Int2Str(v.SkuID), foodData)
}
}
}
}
}
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 SendSeckillSkusCountMsg(ctx *jxcontext.Context, vendorIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
// 1. 如果爆品低于8个报警 type1
// 2. 爆品价格低于1元商品小于5个报警 type2
var (
type1Count = 8
type2Count = 5
ddMsgresult []interface{}
)
db := dao.GetDB()
storeList, err := dao.GetStoresMapList(db, vendorIDs, nil, []int{model.StoreStatusClosed, model.StoreStatusHaveRest, model.StoreStatusOpened}, model.StoreStatusOpened, model.StoreIsSyncAll, "", "", "")
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) {
store := batchItemList[0].(*model.StoreMap)
var type1, type2 int
switch store.VendorID {
case model.VendorIDEBAI:
result, _ := api.EbaiAPI.GetStoresShowWindowSkus(utils.Str2Int64(store.VendorStoreID))
for _, v := range result {
type1++
if v.SalePrice < 1 {
type2++
}
}
case model.VendorIDMTWM:
handler := partner.GetPurchasePlatformFromVendorID(store.VendorID).(partner.ISingleStoreStoreSkuHandler)
remoteSkuList, err := handler.GetStoreSkusFullInfo(ctx, nil, store.StoreID, store.VendorStoreID, nil)
if err != nil {
return retVal, err
}
for _, v := range remoteSkuList {
for _, vv := range v.SkuList {
if vv.IsSpecialty == 1 {
type1++
}
if vv.IsSpecialty == 1 && vv.VendorPrice < 100 {
type2++
}
}
}
case model.VendorIDJD:
var storeSecKill []*tStoreSkusSecKill
sql := `
SELECT t1.store_id,count(*) sec_kill_count, count(t1.price < 100 or NULL) sec_kill_count2
FROM(
SELECT a.store_id, a.sku_id, d.type, MIN(e.actual_act_price) price
FROM store_sku_bind a
LEFT JOIN act_store_sku b ON a.store_id = b.store_id AND b.sku_id = a.sku_id
LEFT JOIN act_map c ON c.act_id = b.act_id
LEFT JOIN act d ON d.id = c.act_id
LEFT JOIN act_store_sku_map e ON e.store_id = a.store_id AND e.sku_id = a.sku_id AND e.vendor_id = c.vendor_id AND e.act_id = d.id
WHERE 1=1
AND a.store_id = ?
AND c.vendor_id = ?
AND NOW() BETWEEN d.begin_at AND d.end_at
AND d.type = ?
AND a.status = ?
AND a.deleted_at = ?
AND e.actual_act_price <> 0
GROUP BY 1,2,3)t1
GROUP BY 1
`
sqlParams := []interface{}{
store.StoreID, store.VendorID,
model.ActSkuSecKill, model.StoreSkuBindStatusNormal,
utils.DefaultTimeValue,
}
err = dao.GetRows(db, &storeSecKill, sql, sqlParams...)
if len(storeSecKill) > 0 {
type1 = storeSecKill[0].SecKillCount
type2 = storeSecKill[0].SecKillCount2
} else {
type1 = 0
type2 = 0
}
}
if type1 < type1Count || type2 < type2Count {
storeDetail, _ := dao.GetStoreDetail(db, store.StoreID, store.VendorID, "")
var (
type1Str = "爆品数量低于8个"
type2Str = "爆品价格小于1元的爆品数量低于5个"
typeResult = ""
)
operatorNameList := jxutils.BatchString2Slice(storeDetail.OperatorName, storeDetail.OperatorName2, storeDetail.OperatorName3)
operatorPhoneList := jxutils.BatchString2Slice(storeDetail.OperatorPhone, storeDetail.OperatorPhone2, storeDetail.OperatorPhone3)
if type1 < type1Count {
typeResult += type1Str
}
if type2 < type2Count {
typeResult += type2Str
}
var result = &tStoreSkusSecKill{}
noticeMsg := fmt.Sprintf("运营负责人:[%v],市场负责人:[%v]门店ID[%v]平台门店ID[%v],门店名:[%v],平台:[%v],警告类型:[%v]\n", strings.Join(operatorNameList, ","), storeDetail.MarketManName, store.StoreID, storeDetail.VendorStoreID, store.StoreName, model.VendorChineseNames[store.VendorID], typeResult)
result.OperatorPhoneList = operatorPhoneList
result.MarketManPhone = storeDetail.MarketManPhone
result.NoticeMsg = noticeMsg
retVal = []*tStoreSkusSecKill{result}
}
return retVal, err
}
taskParallel := tasksch.NewParallelTask("获取各平台爆品数量", tasksch.NewParallelConfig().SetParallelCount(parallelCount), ctx, taskFunc, storeList)
tasksch.HandleTask(taskParallel, task, true).Run()
ddMsgresult, err = taskParallel.GetResult(0)
case 1:
var (
operaterMap = make(map[string]string)
marketMap = make(map[string]string)
)
for _, v := range ddMsgresult {
ddm := v.(*tStoreSkusSecKill)
for _, phone := range ddm.OperatorPhoneList {
if operaterMap[phone] != "" {
operaterMap[phone] += ddm.NoticeMsg
} else {
operaterMap[phone] = ddm.NoticeMsg
}
}
if marketMap[ddm.MarketManPhone] != "" {
marketMap[ddm.MarketManPhone] += ddm.NoticeMsg
} else {
marketMap[ddm.MarketManPhone] = ddm.NoticeMsg
}
}
for k, v := range operaterMap {
if marketMap[k] != "" {
continue
}
user, err := dao.GetUserByID(db, "mobile", k)
if user != nil && err == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "警告!门店爆品数量异常!", v)
}
globals.SugarLogger.Debugf("SendSeckillSkusCountMsg: [%v]", v)
}
for k, v := range marketMap {
if operaterMap[k] != "" {
continue
}
user, err := dao.GetUserByID(db, "mobile", k)
if user != nil && err == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "警告!门店爆品数量异常!", v)
}
globals.SugarLogger.Debugf("SendSeckillSkusCountMsg: [%v]", v)
}
}
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 RefreshJxPriceByVendor(ctx *jxcontext.Context, jdStoreSkus []*JdStoreSkus, vendorID int, ignoreLow, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
db = dao.GetDB()
jdMap = make(map[int][]*JdStoreSkus)
jxMap = make(map[int]map[int]int)
param []*StoreSkuBindInfo
)
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
if vendorID == model.VendorIDJD {
for _, v := range jdStoreSkus {
var (
pricePercentagePack []*model.PricePercentageItem
cats []*model.ThingMap
skus []*model.SkuAndName
vendorPrice int
specQuality float64
)
sql := `
SELECT t1.*
FROM thing_map t1
WHERE t1.deleted_at = ? AND t1.thing_type = ?
AND t1.vendor_thing_id = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.ThingTypeSku,
v.JdSkuID,
}
err = dao.GetRows(db, &cats, sql, sqlParams...)
if len(cats) > 0 {
skus, err = dao.GetSkus(db, []int{int(cats[0].ThingID)}, nil, nil, nil, nil)
if err != nil || len(skus) == 0 {
return result, fmt.Errorf("没有找到该京西skuID,京西skuID :[%v]", cats[0].ThingID)
}
} else {
return result, fmt.Errorf("没有找到该京东skuID对应的京西skuID,京东skuID :[%v]", v.JdSkuID)
}
store, err := dao.GetStoreDetailByVendorStoreID(db, utils.Int2Str(v.JdStoreID), vendorID, "")
if err != nil || store == nil {
return result, fmt.Errorf("没有找到该京东门店对应的京西门店!,京东门店ID :[%v]", v.JdStoreID)
}
err = jxutils.Strings2Objs(store.PricePercentagePackStr, &pricePercentagePack)
if skus[0].Unit == model.SpecialUnit {
if skus[0].SpecUnit == model.SpecUnitNames[1] || skus[0].SpecUnit == model.SpecUnitNames[2] {
specQuality = float64(skus[0].SpecQuality) * 1000
} else {
specQuality = float64(skus[0].SpecQuality)
}
vendorPrice = int(utils.Float64TwoInt64(specQuality / utils.Int2Float64(model.SpecialSpecQuality) * utils.Int2Float64(v.Price)))
} else {
vendorPrice = v.Price
}
jxPrice := jxutils.CaculateJxPriceByPricePack(pricePercentagePack, 0, vendorPrice)
if skus[0].Unit == model.SpecialUnit {
jxPrice = int(utils.Float64TwoInt64(utils.Int2Float64(jxPrice) * utils.Int2Float64(model.SpecialSpecQuality) / specQuality))
}
jdMap[store.ID] = append(jdMap[store.ID], &JdStoreSkus{
JdSkuID: skus[0].NameID,
Price: jxPrice,
})
}
for k, v := range jdMap {
var skuNameMap = make(map[int]int)
for _, vv := range v {
if skuNameMap[vv.JdSkuID] != 0 {
if skuNameMap[vv.JdSkuID] > vv.Price {
skuNameMap[vv.JdSkuID] = vv.Price
}
} else {
skuNameMap[vv.JdSkuID] = vv.Price
}
}
jxMap[k] = skuNameMap
}
for k, v := range jxMap {
for kk, vv := range v {
result, err := dao.GetStoreSkuBindByNameID(db, k, kk, model.SkuStatusNormal)
if len(result) > 0 && err == nil {
if ignoreLow {
if result[0].UnitPrice > vv {
storeSkuBindInfo := &StoreSkuBindInfo{
StoreID: k,
NameID: kk,
UnitPrice: vv,
}
param = append(param, storeSkuBindInfo)
}
} else {
storeSkuBindInfo := &StoreSkuBindInfo{
StoreID: k,
NameID: kk,
UnitPrice: vv,
}
param = append(param, storeSkuBindInfo)
}
}
}
}
} else if vendorID == model.VendorIDMTWM {
for _, v := range jdStoreSkus {
var (
pricePercentagePack []*model.PricePercentageItem
vendorPrice int
specQuality float64
)
skus, _ := dao.GetSkus(db, []int{v.JdSkuID}, nil, nil, nil, nil)
if len(skus) == 0 {
continue
}
store, _ := dao.GetStoreDetail(db, v.JdStoreID, vendorID, "")
err = jxutils.Strings2Objs(store.PricePercentagePackStr, &pricePercentagePack)
if skus[0].Unit == model.SpecialUnit {
if skus[0].SpecUnit == model.SpecUnitNames[1] || skus[0].SpecUnit == model.SpecUnitNames[2] {
specQuality = float64(skus[0].SpecQuality) * 1000
} else {
specQuality = float64(skus[0].SpecQuality)
}
vendorPrice = int(utils.Float64TwoInt64(specQuality / utils.Int2Float64(model.SpecialSpecQuality) * utils.Int2Float64(v.Price)))
} else {
vendorPrice = v.Price
}
jxPrice := jxutils.CaculateJxPriceByPricePack(pricePercentagePack, 0, vendorPrice)
if skus[0].Unit == model.SpecialUnit {
jxPrice = int(utils.Float64TwoInt64(utils.Int2Float64(jxPrice) * utils.Int2Float64(model.SpecialSpecQuality) / specQuality))
}
jdMap[v.JdStoreID] = append(jdMap[v.JdStoreID], &JdStoreSkus{
JdSkuID: skus[0].NameID,
Price: jxPrice,
})
}
for k, v := range jdMap {
var skuNameMap = make(map[int]int)
for _, vv := range v {
if skuNameMap[vv.JdSkuID] != 0 {
if skuNameMap[vv.JdSkuID] > vv.Price {
skuNameMap[vv.JdSkuID] = vv.Price
}
} else {
skuNameMap[vv.JdSkuID] = vv.Price
}
}
jxMap[k] = skuNameMap
}
for k, v := range jxMap {
for kk, vv := range v {
result, err := dao.GetStoreSkuBindByNameID(db, k, kk, model.SkuStatusNormal)
if len(result) > 0 && err == nil {
if ignoreLow {
if result[0].UnitPrice > vv {
storeSkuBindInfo := &StoreSkuBindInfo{
StoreID: k,
NameID: kk,
UnitPrice: vv,
}
param = append(param, storeSkuBindInfo)
}
} else {
storeSkuBindInfo := &StoreSkuBindInfo{
StoreID: k,
NameID: kk,
UnitPrice: vv,
}
param = append(param, storeSkuBindInfo)
}
}
}
}
}
case 1:
_, err = UpdateStoresSkusByBind(ctx, nil, param, isAsync, isContinueWhenError, false)
}
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 RefreshJxPriceByVendor2(ctx *jxcontext.Context, storeIDs []int, vendorID int, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
db = dao.GetDB()
param []*StoreSkuBindInfo
)
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
for _, storeID := range storeIDs {
var (
pricePercentagePack []*model.PricePercentageItem
skuNameMap = make(map[int]int64)
)
storeDetail, _ := dao.GetStoreDetail(db, storeID, vendorID, "")
err = jxutils.Strings2Objs(storeDetail.PricePercentagePackStr, &pricePercentagePack)
if partner.IsMultiStore(vendorID) {
mulitStoreSkuHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
skuList, err := dao.GetSkusWithVendor(db, []int{vendorID}, nil, nil, nil, false)
if err != nil {
return "", err
}
bareStoreSkuMap := make(map[string][]*partner.StoreSkuInfo)
for _, sku := range skuList {
bareStoreSkuMap[sku.VendorOrgCode] = append(bareStoreSkuMap[sku.VendorOrgCode], &partner.StoreSkuInfo{
SkuID: sku.ID,
VendorSkuID: sku.VendorSkuID,
})
}
for _, orgCode := range apimanager.CurAPIManager.GetAppOrgCodeList(vendorID) {
outStoreSkuList, _ := mulitStoreSkuHandler.GetStoreSkusBareInfo(ctx, orgCode, task, storeID, storeDetail.VendorStoreID, bareStoreSkuMap[orgCode])
for _, sku := range outStoreSkuList {
price, nameID := GetSkuNamePrice(db, sku.SkuID, sku.VendorPrice)
if skuNameMap[nameID] < price {
skuNameMap[nameID] = price
}
}
for k, v := range skuNameMap {
unitPrice := jxutils.CaculateJxPriceByPricePack(pricePercentagePack, 0, int(v))
storeSkuBindInfo := &StoreSkuBindInfo{
StoreID: storeID,
NameID: k,
UnitPrice: unitPrice,
}
param = append(param, storeSkuBindInfo)
}
}
} else {
singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
outSkuNameList, _ := singleStoreHandler.GetStoreSkusFullInfo(ctx, task, storeID, storeDetail.VendorStoreID, nil)
for _, skuName := range outSkuNameList {
sku := skuName.SkuList[0]
price, nameID := GetSkuNamePrice(db, sku.SkuID, sku.VendorPrice)
if skuNameMap[nameID] < price {
skuNameMap[nameID] = price
}
}
for k, v := range skuNameMap {
unitPrice := jxutils.CaculateJxPriceByPricePack(pricePercentagePack, 0, int(v))
storeSkuBindInfo := &StoreSkuBindInfo{
StoreID: storeID,
NameID: k,
UnitPrice: unitPrice,
}
param = append(param, storeSkuBindInfo)
}
}
}
case 1:
_, err = UpdateStoresSkusByBind(ctx, nil, param, isAsync, isContinueWhenError, false)
}
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 GetSkuNamePrice(db *dao.DaoDB, skuID int, orgPrice int64) (price int64, nameID int) {
var (
specQuality float64
)
skuList, _ := dao.GetSkus(db, []int{skuID}, nil, nil, nil, nil)
for _, v := range skuList {
if v.Unit == model.SpecialUnit {
if v.SpecUnit == model.SpecUnitNames[1] || v.SpecUnit == model.SpecUnitNames[2] {
specQuality = float64(v.SpecQuality) * 1000
} else {
specQuality = float64(v.SpecQuality)
}
price = utils.Float64TwoInt64(utils.Int2Float64(model.SpecialSpecQuality) / specQuality * utils.Int2Float64(int(orgPrice)))
} else {
price = orgPrice
}
nameID = v.NameID
}
return price, nameID
}
func BackUpStoreSkuBind(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
db = dao.GetDB()
snapshotAt = utils.Time2Date(time.Now())
)
storeSkuBindHis := &model.StoreSkuBindHistory{
SnapshotAt: snapshotAt.AddDate(0, 0, -5),
}
dao.DeleteEntity(db, storeSkuBindHis, "SnapshotAt")
storeList, err := dao.GetStoreList(db, nil, nil, nil, nil, nil, "")
task := tasksch.NewParallelTask("BackUpStoreSkuBind", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
store := batchItemList[0].(*model.Store)
storeSku, err := dao.GetStoresSkusInfo(db, []int{store.ID}, nil)
var storeSkuBindHiss []*model.StoreSkuBindHistory
for _, v := range storeSku {
storeSkuBindHis := &model.StoreSkuBindHistory{}
storeSkuBindHis.StoreSkuBind = *v
storeSkuBindHis.StoreSkuBindID = v.ID
storeSkuBindHis.StoreSkuBind.ID = 0
storeSkuBindHis.SnapshotAt = utils.Time2Date(snapshotAt)
storeSkuBindHiss = append(storeSkuBindHiss, storeSkuBindHis)
}
if len(storeSkuBindHiss) > 0 {
dao.CreateMultiEntities(db, storeSkuBindHiss)
}
return retVal, err
}, storeList)
tasksch.HandleTask(task, nil, true).Run()
if isAsync {
hint = task.GetID()
} else {
_, err = task.GetResult(0)
hint = "1"
}
return hint, err
}
func ReturnStoreSkuBind(ctx *jxcontext.Context, snapshotAt string, storeIDs, skuIDs []int) (err error) {
var (
spAt = utils.Time2Date(utils.Str2Time(snapshotAt))
db = dao.GetDB()
)
if len(storeIDs) == 0 {
return fmt.Errorf("必须选择一个门店!")
}
if len(storeIDs) > 1 {
return fmt.Errorf("暂时只支持一次操作一个门店!")
}
//删除原门店商品
sql := `DELETE FROM store_sku_bind WHERE store_id IN(` + dao.GenQuestionMarks(len(storeIDs)) + `)`
sqlParams := []interface{}{storeIDs}
if len(skuIDs) > 0 {
sql += " AND sku_id IN(" + dao.GenQuestionMarks(len(skuIDs)) + ")"
sqlParams = append(sqlParams, skuIDs)
}
_, err = dao.ExecuteSQL(db, sql, sqlParams)
//查询备份的门店商品
var storeHiss []*model.StoreSkuBindHistory
sql2 := `SELECT * FROM store_sku_bind_history WHERE snapshot_at = ? AND store_id IN(` + dao.GenQuestionMarks(len(storeIDs)) + `)`
sqlParams2 := []interface{}{spAt, storeIDs}
if len(skuIDs) > 0 {
sql2 += " AND sku_id IN(" + dao.GenQuestionMarks(len(skuIDs)) + ")"
sqlParams2 = append(sqlParams2, skuIDs)
}
err = dao.GetRows(db, &storeHiss, sql2, sqlParams2)
//插入到现在
var storeSkus []*model.StoreSkuBind
for _, v := range storeHiss {
storeSku := &model.StoreSkuBind{}
storeSku = &v.StoreSkuBind
storeSku.ID = v.StoreSkuBindID
storeSkus = append(storeSkus, storeSku)
}
if len(storeSkus) > 0 {
dao.CreateMultiEntities(db, storeSkus)
}
return err
}
func RefreshMatterStock(ctx *jxcontext.Context, skuID int) (err error) {
var (
db = dao.GetDB()
skuBindInfos []*StoreSkuBindInfo
)
if skuID != 0 {
skus, err := dao.GetSkus(db, []int{skuID}, nil, nil, nil, nil)
if err != nil || len(skus) == 0 {
return err
}
result, err := api.JdEclpAPI.QueryStock(skus[0].EclpID)
if err != nil || result == nil {
return err
}
var isSale = 0
if len(result) == 0 {
isSale = -1
} else {
if result[0].UsableNum > 0 {
isSale = 1
} else {
isSale = -1
}
}
storeSkuList, _ := dao.GetStoresSkusInfo(db, nil, []int{skuID})
for _, vv := range storeSkuList {
var storeSkuBindSkus []*StoreSkuBindSkuInfo
storeSkuBindSku := &StoreSkuBindSkuInfo{
SkuID: vv.SkuID,
IsSale: isSale,
}
storeSkuBindSkus = append(storeSkuBindSkus, storeSkuBindSku)
storeSkuBind := &StoreSkuBindInfo{
StoreID: vv.StoreID,
// NameID: v.SkuNameID,
Skus: storeSkuBindSkus,
}
skuBindInfos = append(skuBindInfos, storeSkuBind)
}
} else {
result, err := api.JdEclpAPI.QueryStock("")
if err != nil {
return err
}
for _, v := range result {
skus, err := dao.GetSkus(db, nil, nil, nil, nil, []string{v.GoodsNo})
if err != nil || len(skus) == 0 {
continue
}
var isSale = 0
if v.UsableNum > 0 {
isSale = 1
} else {
isSale = -1
}
storeSkuList, _ := dao.GetStoresSkusInfo(db, nil, []int{skus[0].ID})
for _, vv := range storeSkuList {
var storeSkuBindSkus []*StoreSkuBindSkuInfo
storeSkuBindSku := &StoreSkuBindSkuInfo{
SkuID: vv.SkuID,
IsSale: isSale,
}
storeSkuBindSkus = append(storeSkuBindSkus, storeSkuBindSku)
storeSkuBind := &StoreSkuBindInfo{
StoreID: vv.StoreID,
NameID: skus[0].NameID,
Skus: storeSkuBindSkus,
}
skuBindInfos = append(skuBindInfos, storeSkuBind)
}
}
}
//物料店666666
updateStoresSkusWithoutSync(ctx, db, []int{666666}, skuBindInfos, false, false)
return err
}
func buildStoreSkuBindInfosAndFocus(ctx *jxcontext.Context, db *dao.DaoDB, store *dao.StoreDetail, v *partner.SkuNameInfo, nameID int) (err error) {
var (
pricePercentagePack []*model.PricePercentageItem
pricePercentagePack2 []*model.PricePercentageItem
jxPrice = 0
)
skus, _ := dao.GetSkus(db, nil, []int{nameID}, nil, nil, nil)
err = jxutils.Strings2Objs(store.PricePercentagePackStr, &pricePercentagePack)
price := jxutils.CaculateJxPriceByPricePack(pricePercentagePack, 0, int(v.SkuList[0].VendorPrice))
store2, _ := dao.GetStoreDetail(db, store.ID, model.VendorIDJX, "")
if store2 != nil {
err = jxutils.Strings2Objs(store2.PricePercentagePackStr, &pricePercentagePack2)
jxPrice = jxutils.CaculatePriceByPricePack(pricePercentagePack2, 0, price)
}
skuBind := &model.StoreSkuBind{
StoreID: store.ID,
UnitPrice: price,
Price: price,
Status: model.StoreSkuBindStatusNormal,
YbID: utils.Str2Int64(v.SkuList[0].VendorSkuID),
YbPrice: int(v.SkuList[0].VendorPrice),
JxPrice: jxPrice,
YbSyncStatus: 0,
MtwmSyncStatus: model.SyncFlagNewMask,
JdSyncStatus: model.SyncFlagNewMask,
EbaiSyncStatus: model.SyncFlagNewMask,
}
if len(skus) > 0 {
skuBind.SkuID = skus[0].ID
}
dao.WrapAddIDCULDEntity(skuBind, ctx.GetUserName())
err = dao.CreateEntity(db, skuBind)
return err
}
func CreateSkusAndFocusFromWx(ctx *jxcontext.Context, productInfo *jdapi.ProductInfo, price, storeID int) (err error) {
var (
db = dao.GetDB()
skuBindInfos []*StoreSkuBindInfo
outSkuNameExt *model.SkuNameExt
)
if productInfo == nil {
return fmt.Errorf("未查询到相关商品!")
}
if price == 0 {
return fmt.Errorf("请输入商品价格!")
}
focusSku := func(nameID int) {
skuBindInfo := &StoreSkuBindInfo{
StoreID: storeID,
NameID: nameID,
UnitPrice: price,
IsFocus: 1,
IsSale: 1,
}
skuBindInfos = append(skuBindInfos, skuBindInfo)
_, err := UpdateStoresSkusByBind(ctx, nil, skuBindInfos, true, true, false)
if err != nil {
err = nil
}
}
skuNames, err := dao.GetSkuNames(db, nil, []string{productInfo.UpcCode}, "", false)
if err != nil {
return err
}
if len(skuNames) == 0 {
if productInfo.Name == "" {
var originName string
if strings.Contains(productInfo.OriginalName, upcSpecName1) {
originName = strings.ReplaceAll(productInfo.OriginalName, upcSpecName1, "")
}
if strings.Contains(productInfo.OriginalName, "*") {
originName = strings.ReplaceAll(productInfo.OriginalName, "*", "")
}
_, name, _, specUnit, unit, specQuality := jxutils.SplitSkuName(originName)
productInfo.Name = name
productInfo.SpecQuality = specQuality
productInfo.Unit = unit
productInfo.SpecUnit = specUnit
}
if productInfo.Name == "" {
if result, err := api.MtwmAPI.GetStandardProductListWithCond(productInfo.UpcCode); err == nil && result != nil {
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
}
}
skuNameExt := &model.SkuNameExt{
SkuName: model.SkuName{
Name: productInfo.Name,
Upc: &productInfo.UpcCode,
Status: model.SkuStatusNormal,
CategoryID: model.NoCatCatgoryID,
IsGlobal: model.YES,
Unit: productInfo.Unit,
},
Skus: []*model.SkuWithVendor{
&model.SkuWithVendor{
Sku: &model.Sku{},
},
},
// Places: []int{510100}, //默认成都
}
skuNameExt.Price = price
skuNameExt.Skus[0].SpecQuality = productInfo.SpecQuality
skuNameExt.Skus[0].SpecUnit = productInfo.SpecUnit
skuNameExt.Skus[0].Weight = int(utils.Str2Int64(utils.Float64ToStr(float64(productInfo.Weight))))
skuNameExt.Skus[0].Status = model.SkuStatusNormal
if len(productInfo.ImgList) > 0 {
setImgs(skuNameExt, productInfo.ImgList)
}
//可能就是没查出来
if skuNameExt.Name == "" {
skuNameExt.Name = productInfo.OriginalName
skuNameExt.Unit = model.UnitNames[5]
skuNameExt.Skus[0].SpecQuality = 100
skuNameExt.Skus[0].SpecUnit = model.SpecUnitNames[0]
skuNameExt.Skus[0].Weight = 100
}
outSkuNameExt, err = AddSkuName(ctx, skuNameExt, ctx.GetUserName())
if err != nil {
if _, ok := err.(*SyncError); ok {
err = nil
} else {
return err
}
} else {
focusSku(outSkuNameExt.ID)
}
} else {
focusSku(skuNames[0].ID)
}
return err
}
func SyncMatterC4ToGy(ctx *jxcontext.Context, isContinueWhenError, isAsync bool) (hint string, err error) {
var (
db = dao.GetDB()
skus []*model.Sku
skusgy []*model.Sku
eclpIDs []string
addMatters []*model.Sku
deleteMatters []*model.Sku
updateMatters []*model.Sku
)
if globals.IsMainProductEnv() {
return "", fmt.Errorf("此接口只允许在果园上调用!")
}
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)
var (
skusMap = make(map[string]*model.Sku)
skusgyMap = make(map[string]*model.Sku)
)
switch step {
case 0:
sql := "SELECT * FROM jxd_dev_0.sku WHERE deleted_at = ? AND eclp_id <> ''"
sqlParams := []interface{}{utils.DefaultTimeValue}
err = dao.GetRows(db, &skus, sql, sqlParams)
for _, c4 := range skus {
eclpIDs = append(eclpIDs, c4.EclpID)
skusMap[c4.EclpID] = c4
}
sql2 := "SELECT * FROM sku WHERE deleted_at = ? AND eclp_id IN (" + dao.GenQuestionMarks(len(eclpIDs)) + ")"
sqlParams = append(sqlParams, eclpIDs)
err = dao.GetRows(db, &skusgy, sql2, sqlParams)
for _, gy := range skusgy {
skusgyMap[gy.EclpID] = gy
if skusMap[gy.EclpID] == nil {
deleteMatters = append(deleteMatters, skusgyMap[gy.EclpID])
}
}
for _, c4 := range skus {
if skusgyMap[c4.EclpID] == nil {
addMatters = append(addMatters, skusMap[c4.EclpID])
} else {
updateMatters = append(updateMatters, skusMap[c4.EclpID])
}
}
case 1:
if len(deleteMatters) > 0 {
for _, v := range deleteMatters {
_, err = DeleteSkuName(ctx, v.NameID, ctx.GetUserName())
}
}
if len(addMatters) > 0 {
for _, v := range addMatters {
var (
skuName *model.SkuName
skuNames []*model.SkuName
)
sql := `
SELECT t1.*
FROM jxd_dev_0.sku_name t1
WHERE t1.deleted_at = ?
AND t1.id = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue, v.NameID}
err = dao.GetRows(db, &skuNames, sql, sqlParams)
if len(skuNames) > 0 {
skuName = skuNames[0]
}
skuNameExt := &model.SkuNameExt{
SkuName: model.SkuName{},
Skus: []*model.SkuWithVendor{
&model.SkuWithVendor{
Sku: &model.Sku{},
},
},
}
skuNameExt.Unit = skuName.Unit
skuNameExt.Name = skuName.Name
skuNameExt.Upc = skuName.Upc
skuNameExt.Img = skuName.Img
skuNameExt.Img2 = skuName.Img2
skuNameExt.DescImg = skuName.DescImg
skuNameExt.Price = skuName.Price
skuNameExt.IsGlobal = model.YES
skuNameExt.Status = model.SkuStatusNormal
// skuNameExt.ID = v.NameID
skuNameExt.CategoryID = 3024 //默认全放物料分类下
skuNameExt.DeletedAt = utils.DefaultTimeValue
skuNameExt.CreatedAt = time.Now()
skuNameExt.LastOperator = ctx.GetUserName()
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if err = dao.CreateEntity(db, &skuNameExt.SkuName); err != nil {
dao.Rollback(db)
return retVal, err
}
// skuNameExt.Skus[0].ID = v.ID
skuNameExt.Skus[0].SpecQuality = v.SpecQuality
skuNameExt.Skus[0].SpecUnit = v.SpecUnit
skuNameExt.Skus[0].EclpID = v.EclpID
skuNameExt.Skus[0].Status = model.SkuStatusNormal
skuNameExt.Skus[0].NameID = skuNameExt.ID
skuNameExt.Skus[0].DeletedAt = utils.DefaultTimeValue
skuNameExt.Skus[0].CreatedAt = time.Now()
skuNameExt.Skus[0].LastOperator = ctx.GetUserName()
if err = dao.CreateEntity(db, skuNameExt.Skus[0].Sku); err != nil {
dao.Rollback(db)
return retVal, err
}
dao.Commit(db)
focusC4Matters(ctx, db, v)
}
}
if len(updateMatters) > 0 {
for _, v := range updateMatters {
var (
skuName *model.SkuName
skuNames []*model.SkuName
)
sql := `
SELECT t1.*
FROM jxd_dev_0.sku_name t1, jxd_dev_0.sku t2
WHERE t1.id = t2.name_id
AND t1.deleted_at = ?
AND t2.eclp_id = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue, v.EclpID}
err = dao.GetRows(db, &skuNames, sql, sqlParams)
if len(skuNames) > 0 {
skuName = skuNames[0]
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
if v != nil {
sql := `
UPDATE sku SET spec_quality = ?, spec_unit = ?, eclp_id = ?, last_operator = ?
WHERE eclp_id = ?
AND deleted_at = ?
`
sqlParams := []interface{}{v.SpecQuality, v.SpecUnit, v.EclpID, ctx.GetUserName(), v.EclpID, utils.DefaultTimeValue}
if _, err = dao.ExecuteSQL(db, sql, sqlParams); err != nil {
dao.Rollback(db)
return retVal, err
}
}
if skuName != nil {
sql := `
UPDATE sku_name a
JOIN sku b ON a.id = b.name_id
SET a.name = ?, a.img = ?, a.img2 = ?, a.desc_img = ?, a.unit = ?, a.price = ?, a.last_operator = ?
WHERE b.eclp_id = ?
AND a.deleted_at = ?
AND 1=1
`
sqlParams := []interface{}{skuName.Name, skuName.Img, skuName.Img2, skuName.DescImg, skuName.Unit, skuName.Price,
ctx.GetUserName(), v.EclpID, utils.DefaultTimeValue}
if _, err = dao.ExecuteSQL(db, sql, sqlParams); err != nil {
dao.Rollback(db)
return retVal, err
}
}
dao.Commit(db)
focusC4Matters(ctx, db, v)
}
}
}
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 focusC4Matters(ctx *jxcontext.Context, db *dao.DaoDB, v *model.Sku) (err error) {
var storeSkus []*model.StoreSkuBind
sql := `
SELECT *
FROM jxd_dev_0.store_sku_bind a, jxd_dev_0.sku b
WHERE a.sku_id = b.id
AND a.store_id = ?
AND b.eclp_id = ?
AND a.deleted_at = ?
`
sqlParams2 := []interface{}{model.MatterStoreID, v.EclpID, utils.DefaultTimeValue}
err = dao.GetRows(db, &storeSkus, sql, sqlParams2)
if err != nil {
return err
}
if len(storeSkus) > 0 {
var (
skuBindInfos []*StoreSkuBindInfo
skuName2 *model.SkuName
)
sql := `
SELECT a.* FROM sku_name a, sku b WHERE a.id = b.name_id AND b.eclp_id = ? AND a.deleted_at = ?
`
sqlParams := []interface{}{v.EclpID, utils.DefaultTimeValue}
err = dao.GetRow(db, &skuName2, sql, sqlParams)
if skuName2 != nil {
skuBindInfo := &StoreSkuBindInfo{
NameID: skuName2.ID,
IsFocus: 1,
UnitPrice: skuName2.Price,
}
skuBindInfos = append(skuBindInfos, skuBindInfo)
}
updateStoresSkusWithoutSync(ctx, db, []int{model.MatterStoreID}, skuBindInfos, false, false)
}
return err
}
func RefreshJdsSkusStatus(ctx *jxcontext.Context) (err error) {
handler := partner.GetPurchasePlatformFromVendorID(model.VendorIDJDShop).(partner.ISingleStoreStoreSkuHandler)
remoteSkuList, err := handler.GetStoreSkusFullInfo(ctx, nil, 0, "", nil)
for _, v := range remoteSkuList {
if v.Status == jdshopapi.JdsSkuStatus2 {
reason, err := api.JdShopAPI.FindOpReason(utils.Str2Int64(v.VendorNameID))
if err == nil && reason == jdshopapi.PassReason {
err = api.JdShopAPI.UpOrDown(utils.Str2Int64(v.VendorNameID), jdshopapi.JdsSkuStatus1)
}
}
}
return err
}
func GetStoreSkuAudit(ctx *jxcontext.Context, storeIDs, nameIDs, skuIDs, statuss, types []int, name, remark, keyword, cityName, marketManPhone, applyTimeStart, applyTimeEnd, auditTimeStart, auditTimeEnd string, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
var (
applyTimeStartp, applyTimeEndp, auditTimeStartp, auditTimeEndp time.Time
)
if applyTimeStart != "" {
applyTimeStartp = utils.Str2Time(applyTimeStart)
}
if applyTimeEnd != "" {
applyTimeEndp = utils.Str2Time(applyTimeEnd)
}
if auditTimeStart != "" {
auditTimeStartp = utils.Str2Time(auditTimeStart)
}
if auditTimeEnd != "" {
auditTimeEndp = utils.Str2Time(auditTimeEnd)
}
//权限
if permission.IsRoled(ctx) {
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
var storeIDs2 []int
if len(storeIDs) > 0 {
for _, v := range storeIDs {
if storeIDsMap[v] != 0 {
storeIDs2 = append(storeIDs2, v)
}
}
if len(storeIDs2) == 0 {
storeIDs2 = append(storeIDs2, -1)
}
} else {
for k, _ := range storeIDsMap {
storeIDs2 = append(storeIDs2, k)
}
}
storeIDs = nil
storeIDs = storeIDs2
}
}
pagedInfo, err = dao.GetStoreSkuAudit(dao.GetDB(), storeIDs, nameIDs, skuIDs, statuss, types, name, remark, keyword, marketManPhone, cityName, applyTimeStartp, applyTimeEndp, auditTimeStartp, auditTimeEndp, pageSize, offset)
return pagedInfo, err
}
func doStoreSkuAudit(ctx *jxcontext.Context, storeIDs []int, skuBindInfos []*StoreSkuBindInfo) (isAudit bool, err error) {
globals.SugarLogger.Debugf("doStoreSkuAudit storeIDs: %v", storeIDs)
time.Sleep(time.Second / 5)
db := dao.GetDB()
for _, storeID := range storeIDs {
stores, _ := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, nil, "")
//扣点的门店改价不进审核
if len(stores) > 0 {
if stores[0].PayPercentage <= 50 || stores[0].StoreLevel == "E" || stores[0].StoreLevel == "D" {
globals.SugarLogger.Debugf("doStoreSkuAudit return0 storeID : %v", storeID)
return false, err
}
}
for _, skuBindInfo := range skuBindInfos {
globals.SugarLogger.Debugf("doStoreSkuAudit storeID: %v , nameID: %v", storeID, skuBindInfo.NameID)
storeAudits, err := dao.GetStoreSkuAuditLight(db, []int{storeID}, []int{skuBindInfo.NameID}, model.StoreAuditStatusOnline)
//取消关注,可售排除
if skuBindInfo.IsFocus == -1 || skuBindInfo.IsSale != 0 || skuBindInfo.UnitPrice == 0 {
globals.SugarLogger.Debugf("doStoreSkuAudit return1 storeID : %v nameID: %v", storeID, skuBindInfo.NameID)
return false, err
}
if ctx.GetLoginType() != weixin.AuthTypeMP && ctx.GetLoginType() != weixin.AuthTypeMini && ctx.GetLoginType() != weixin.AuthTypeWxApp && ctx.GetLoginType() != auth2.AuthTypeMobile {
globals.SugarLogger.Debugf("doStoreSkuAudit return3 storeID : %v loginType: %v", storeID, ctx.GetLoginType())
authInfo, err := ctx.GetV2AuthInfo()
if err == nil && authInfo != nil && (ctx.GetFullUser().Type&model.UserTypeOperator) != 0 {
if len(storeAudits) > 0 {
storeAudits[0].DeletedAt = time.Now()
dao.UpdateEntity(db, storeAudits[0], "DeletedAt")
// if globals.IsProductEnv() {
// skuAndNames, err := dao.GetSkus(db, nil, []int{skuBindInfo.NameID}, nil, nil, nil)
// if len(skuAndNames) > 0 && err == nil {
// weixinmsg.NotifyStoreOpRequestStatus(true, storeID, skuBindInfo.NameID, jxutils.ComposeSpuName(skuAndNames[0].Prefix, skuAndNames[0].Name, 0), storeAudits[0].OriginUnitPrice, skuBindInfo.UnitPrice, "")
// }
// }
}
globals.SugarLogger.Debugf("doStoreSkuAudit return3 storeID : %v nameID: %v", storeID, skuBindInfo.NameID)
return false, err
}
}
storeSkuAudit := &model.StoreSkuAudit{
StoreID: storeID,
NameID: skuBindInfo.NameID,
Status: model.StoreAuditStatusOnline,
UnitPrice: skuBindInfo.UnitPrice,
}
//如果是关注改价
if skuBindInfo.IsFocus == 1 {
if len(storeAudits) > 0 {
storeAudits[0].DeletedAt = time.Now()
dao.UpdateEntity(db, storeAudits[0], "DeletedAt")
}
storeSkuAudit.Type = model.StoreSkuAuditTypeFocus
} else {
storeSkus, err := dao.GetStoreSkusByNameIDs(db, []int{storeID}, skuBindInfo.NameID)
if len(storeSkus) > 0 {
//如果改的价比原价低排除
if skuBindInfo.UnitPrice <= int(storeSkus[0].UnitPrice) {
if len(storeAudits) > 0 {
storeAudits[0].DeletedAt = time.Now()
dao.UpdateEntity(db, storeAudits[0], "DeletedAt")
}
globals.SugarLogger.Debugf("doStoreSkuAudit return4 storeID : %v nameID: %v", storeID, skuBindInfo.NameID)
return false, err
} else {
if len(storeAudits) > 0 {
storeAudits[0].DeletedAt = time.Now()
dao.UpdateEntity(db, storeAudits[0], "DeletedAt")
}
globals.SugarLogger.Debugf("doStoreSkuAudit cover storeID : %v nameID: %v", storeID, skuBindInfo.NameID)
}
} else {
return false, fmt.Errorf("未查询到该门店商品价storeID: %v, nameID: %V", storeID, skuBindInfo.NameID)
}
storeSkuAudit.Type = model.StoreSkuAuditTypePrice
storeSkuAudit.OriginUnitPrice = int(storeSkus[0].UnitPrice)
}
dao.WrapAddIDCULDEntity(storeSkuAudit, ctx.GetUserName())
err = dao.CreateEntity(db, storeSkuAudit)
}
}
return true, err
}
func StoreSkuPriceAudit(ctx *jxcontext.Context, storeSkuAudits []*model.StoreSkuAudit, status int, isAsync, isContinueWhenError bool) (storeSkuAudits2 []*model.StoreSkuAudit, hint string, err error) {
db := dao.GetDB()
if status == model.StoreAuditStatusOnline {
return nil, "", fmt.Errorf("审核标志不正确!")
}
//证明是预审核
if status == 2 {
for _, v := range storeSkuAudits {
skuList, _ := dao.GetStoreSkusByNameIDs(db, []int{v.StoreID}, v.NameID)
if len(skuList) > 0 {
if int64(v.AuditPrice) > skuList[0].UnitPrice*2 {
storeSkuAudits2 = append(storeSkuAudits2, v)
}
}
}
return storeSkuAudits2, "", err
}
deletedDuplicateWaitAuditData(ctx, db)
task := tasksch.NewParallelTask("StoreSkuPriceAudit", tasksch.NewParallelConfig().SetParallelCount(5).SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeAudit := batchItemList[0].(*model.StoreSkuAudit)
storeAudits, err := dao.GetStoreSkuAuditLight(db, []int{storeAudit.StoreID}, []int{storeAudit.NameID}, model.StoreAuditStatusOnline)
if len(storeAudits) == 0 || err != nil {
return retVal, err
}
if len(storeAudits) > 1 {
return retVal, fmt.Errorf("查询到该门店该商品的待审核信息大于1条storeID: %v, nameID: %v", storeAudit.StoreID, storeAudit.NameID)
}
//审核通过
if status == model.StoreAuditStatusCreated {
storeAudits[0].UserID = ctx.GetUserID()
storeAudits[0].Status = model.StoreAuditStatusCreated
storeAudits[0].Remark = storeAudit.Remark
storeAudits[0].AuditPrice = storeAudit.AuditPrice
_, err = dao.UpdateEntity(db, storeAudits[0], "UserID", "Status", "Remark", "AuditPrice")
var skuBindInfos = []*StoreSkuBindInfo{
&StoreSkuBindInfo{
NameID: storeAudit.NameID,
UnitPrice: storeAudits[0].UnitPrice,
},
}
//证明填了额外的审核价格
if storeAudit.AuditPrice != 0 {
skuBindInfos[0].UnitPrice = storeAudit.AuditPrice
}
//如果是关注改价
if storeAudits[0].Type == model.StoreSkuAuditTypeFocus {
skuBindInfos[0].IsFocus = 1
}
var num int64
db := dao.GetDB()
skuIDs, err := updateStoresSkusWithoutSync(ctx, db, []int{storeAudit.StoreID}, skuBindInfos, false, false)
if err != nil {
return "", err
}
isAsync = asyncStoreSkuOpFilter(ctx, isAsync)
num = int64(len(skuIDs))
if num > 0 {
hint, err = CurVendorSync.SyncStoresSkus(ctx, nil, 0, db, nil, []int{storeAudit.StoreID}, skuIDs, false, isAsync, isContinueWhenError)
}
if num == 0 || !isAsync || hint == "" {
hint = utils.Int64ToStr(num)
}
} else if status == model.StoreAuditStatusRejected {
storeAudits[0].UserID = ctx.GetUserID()
storeAudits[0].Status = model.StoreAuditStatusRejected
storeAudits[0].Remark = storeAudit.Remark
_, err = dao.UpdateEntity(db, storeAudits[0], "UserID", "Status", "Remark")
} else {
return retVal, fmt.Errorf("审核标志不正确!")
}
//TODO 暂时先不推消息了
if err == nil {
// if globals.IsProductEnv() {
// skuAndNames, err := dao.GetSkus(db, nil, []int{storeAudit.NameID}, nil, nil, nil)
// if len(skuAndNames) > 0 && err == nil {
// price := 0
// if storeAudit.AuditPrice != 0 {
// price = storeAudit.AuditPrice
// } else {
// price = storeAudits[0].UnitPrice
// }
// weixinmsg.NotifyStoreOpRequestStatus(flag, storeAudit.StoreID, storeAudit.NameID, jxutils.ComposeSpuName(skuAndNames[0].Prefix, skuAndNames[0].Name, 0), storeAudits[0].OriginUnitPrice, price, storeAudit.Remark)
// }
// }
}
return retVal, err
}, storeSkuAudits)
tasksch.HandleTask(task, nil, true).Run()
if isAsync {
hint = task.GetID()
} else {
_, err = task.GetResult(0)
hint = "1"
}
return nil, hint, err
}
func deletedDuplicateWaitAuditData(ctx *jxcontext.Context, db *dao.DaoDB) {
var (
duplicateDatas []*model.StoreSkuAudit
duplicateStore = make(map[int][]*model.StoreSkuAudit)
)
sql := `
SELECT a.*
FROM store_sku_audit a ,
(
SELECT count(*), store_id ,name_id ,status, deleted_at
FROM store_sku_audit
WHERE status = 0
AND deleted_at = ?
GROUP BY 2,3,4,5
HAVING count(*) > 1
) b
WHERE a.store_id = b.store_id
AND a.name_id = b.name_id
AND a.status= b.status
AND a.deleted_at = b.deleted_at
`
sqlParams := []interface{}{utils.DefaultTimeValue}
dao.GetRows(db, &duplicateDatas, sql, sqlParams)
for _, v := range duplicateDatas {
duplicateStore[v.StoreID] = append(duplicateStore[v.StoreID], v)
}
for _, v := range duplicateStore {
duplicateSkuName := make(map[int][]*model.StoreSkuAudit)
for _, vv := range v {
duplicateSkuName[vv.NameID] = append(duplicateSkuName[vv.NameID], vv)
}
for _, vv := range duplicateSkuName {
for i := 0; i < len(vv)-1; i++ {
dao.DeleteEntity(db, vv[i])
}
}
}
}
func GetSpecialtyStoreSkus(ctx *jxcontext.Context, storeIDs, vendorIDs []int) (err error) {
type SpecialtyStoreSkus struct {
StoreID int `json:"门店ID"`
StoreName string `json:"门店名"`
SkuID int `json:"SkuID"`
SkuName string `json:"商品名"`
Price float64 `json:"平台价"`
VendorName string `json:"平台名"`
}
var (
db = dao.GetDB()
specialtyStoreSkus []*SpecialtyStoreSkus
excelTitle = []string{
"门店ID",
"门店名",
"SkuID",
"商品名",
"平台价",
"平台名",
}
sheetList []*excel.Obj2ExcelSheetConfig
downloadURL, fileName string
)
for _, v := range vendorIDs {
for _, vv := range storeIDs {
storeDetail, err := dao.GetStoreDetail(db, vv, v, "")
if err != nil || storeDetail == nil {
continue
}
if partner.IsMultiStore(v) {
var (
page = 1
vendorSkuIDs []string
)
_, totalCount, _ := api.JdPageAPI.GetJdTopSkus(storeDetail.VendorStoreID, page)
for ; page < totalCount/10+1; page++ {
result, _, _ := api.JdPageAPI.GetJdTopSkus(storeDetail.VendorStoreID, page)
vendorSkuIDs = append(vendorSkuIDs, result...)
}
for _, vvv := range vendorSkuIDs {
thingMap := &model.ThingMap{}
sql := `
SELECT * FROM thing_map WHERE thing_type = 3 AND vendor_thing_id = ? AND vendor_org_code = 320406
AND deleted_at = ?
`
sqlParams := []interface{}{
vvv, utils.DefaultTimeValue,
}
dao.GetRow(db, &thingMap, sql, sqlParams)
skus, _ := dao.GetSkus(db, []int{int(thingMap.ThingID)}, nil, nil, nil, nil)
specialtyStoreSku := &SpecialtyStoreSkus{
StoreID: vv,
StoreName: storeDetail.Name,
SkuID: int(thingMap.ThingID),
SkuName: skus[0].Name,
Price: 0,
VendorName: model.VendorNames[v],
}
specialtyStoreSkus = append(specialtyStoreSkus, specialtyStoreSku)
}
} else {
handler := partner.GetPurchasePlatformFromVendorID(v).(partner.ISingleStoreStoreSkuHandler)
skuList, _ := handler.GetStoreSkusFullInfo(ctx, nil, vv, storeDetail.VendorStoreID, nil)
for _, sku := range skuList {
if sku.SkuList[0].IsSpecialty == model.YES {
specialtyStoreSku := &SpecialtyStoreSkus{
StoreID: vv,
StoreName: storeDetail.Name,
SkuID: sku.SkuList[0].SkuID,
SkuName: sku.Name,
Price: float64(sku.SkuList[0].VendorPrice) / 100,
VendorName: model.VendorNames[v],
}
specialtyStoreSkus = append(specialtyStoreSkus, specialtyStoreSku)
}
}
}
}
}
excelConf := &excel.Obj2ExcelSheetConfig{
Title: "sheet1",
Data: specialtyStoreSkus,
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
}
func checkActUpdate(actID int, actMap map[int]*model.Act2) (err error) {
if len(actMap) == 0 {
return fmt.Errorf("活动%d不存在或已被取消", actID)
}
errList := errlist.New()
for vendorID, act := range actMap {
if vendorID == model.VendorIDEBAI && act.CreateType != model.ActCreateTypeAPI {
errList.AddErr(fmt.Errorf("饿百平台不支持修改或取消网页活动"))
}
}
return errList.GetErrListAsOne()
}
func DeleteActStoreSkuBind(ctx *jxcontext.Context, db *dao.DaoDB, actID int, actStoreSkuParam []*ActStoreSkuParam) (originSyncStatus int8, err error) {
actMap, err := dao.GetActVendorInfo(db, actID, nil)
if err != nil {
return 0, err
}
if err = checkActUpdate(actID, actMap); err != nil {
return 0, err
}
actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, nil, nil, nil)
if err != nil {
return 0, err
}
act := actMap[partner.GetVendorIDsFromActMap(actMap)[0]]
if act.Status != model.ActStatusCreated || time.Now().Sub(act.EndAt) > 0 {
return 0, fmt.Errorf("当前活动状态:%s不能进行此操作或已过期", model.ActStatusName[act.Status])
}
dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db)
if r != nil {
panic(r)
}
}
}()
actStoreSkuParamMap := make(map[int64]*ActStoreSkuParam)
for _, v := range actStoreSkuParam {
actStoreSkuParamMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] = v
if _, err = dao.DeleteEntityLogically(db, &model.ActStoreSku{}, nil, ctx.GetUserName(),
map[string]interface{}{
model.FieldActID: actID,
model.FieldStoreID: v.StoreID,
model.FieldSkuID: v.SkuID,
}); err != nil {
return 0, err
}
}
isNeedCancelAct := true
for vendorID, act := range actMap {
originSyncStatus |= act.SyncStatus
isDeleteAll := true
isDeleteAtLeastOne := false
if true { //actStoreSkuParam != nil {
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuMap[vendorID])
for storeID := range actStoreSkuMap {
for _, actStoreSku := range actStoreSkuMap[storeID] {
if actStoreSkuParam == nil || actStoreSkuParamMap[jxutils.Combine2Int(actStoreSku.StoreID, actStoreSku.SkuID)] != nil {
if act.Type == model.ActSkuFake {
_, err = dao.DeleteEntityLogically(db, &model.ActStoreSkuMap{}, nil, ctx.GetUserName(),
map[string]interface{}{
model.FieldActID: actID,
model.FieldStoreID: actStoreSku.StoreID,
model.FieldSkuID: actStoreSku.SkuID,
})
} else {
_, err = dao.UpdateEntityLogically(db, partner.ActStoreSku2ActStoreSkuMap(actStoreSku),
map[string]interface{}{
model.FieldSyncStatus: actStoreSku.SyncStatus | model.SyncFlagDeletedMask,
}, ctx.GetUserName(), nil)
}
if err != nil {
return 0, err
}
isDeleteAtLeastOne = true
} else {
isNeedCancelAct = false
isDeleteAll = false
}
}
}
} else {
isDeleteAll = true
isDeleteAtLeastOne = true
}
if isDeleteAll || isDeleteAtLeastOne {
syncStatus := int8(model.SyncFlagModifiedMask)
if isDeleteAll {
syncStatus = model.SyncFlagDeletedMask
}
syncStatus |= act.SyncStatus
if act.Type != model.ActSkuFake && vendorID != model.VendorIDJX {
if _, err = dao.UpdateEntityLogically(db, partner.Act2ActMap(act),
map[string]interface{}{
model.FieldSyncStatus: syncStatus,
}, ctx.GetUserName(), nil); err != nil {
return 0, err
}
}
}
if isDeleteAll != isNeedCancelAct {
globals.SugarLogger.Warnf("deleteActStoreBind, actID:%d isDeleteAll:%t != isNeedCancelAct:%t", act.ID, isDeleteAll, isNeedCancelAct)
}
}
if isNeedCancelAct {
act := &model.Act{}
act.ID = actID
if _, err = dao.UpdateEntityLogically(db, act,
map[string]interface{}{
model.FieldStatus: model.ActStatusCanceled,
}, ctx.GetUserName(), nil); err != nil {
return 0, err
}
}
dao.Commit(db)
return originSyncStatus, err
}
func GetVendorStoreSkus(ctx *jxcontext.Context, storeID, vendorID int) (err error) {
type SpecialtyStoreSkus struct {
Upc string `json:"商品upc码"`
SkuName string `json:"商品名"`
Unit string `json:"单位"`
Weight int `json:"重量(g)"`
Price int64 `json:"售价"`
}
var (
db = dao.GetDB()
specialtyStoreSkus []*SpecialtyStoreSkus
excelTitle = []string{
"商品upc码",
"商品名",
"单位",
"重量(g)",
"售价",
}
sheetList []*excel.Obj2ExcelSheetConfig
downloadURL, fileName string
)
storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID, "")
if err != nil || storeDetail == nil {
return err
}
if partner.IsMultiStore(vendorID) {
// handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
// skuBareInfoList, _ := handler.GetStoreSkusBareInfo(ctx, storeDetail.VendorOrgCode, nil, storeID, storeDetail.VendorStoreID, nil)
return fmt.Errorf("暂不支持京东!")
} else {
handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
skuList, _ := handler.GetStoreSkusFullInfo(ctx, nil, storeID, storeDetail.VendorStoreID, nil)
for _, sku := range skuList {
if sku.UPC != "" {
skus := &SpecialtyStoreSkus{
Upc: sku.UPC,
SkuName: sku.Name,
Unit: sku.Unit,
Weight: sku.SkuList[0].Weight,
Price: sku.SkuList[0].VendorPrice,
}
specialtyStoreSkus = append(specialtyStoreSkus, skus)
}
}
}
excelConf := &excel.Obj2ExcelSheetConfig{
Title: "sheet1",
Data: specialtyStoreSkus,
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
}