943 lines
31 KiB
Go
943 lines
31 KiB
Go
package act
|
||
|
||
import (
|
||
"fmt"
|
||
"math"
|
||
"time"
|
||
|
||
"git.rosy.net.cn/baseapi/utils"
|
||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/jsonerr"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||
"git.rosy.net.cn/jx-callback/business/model"
|
||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||
)
|
||
|
||
const (
|
||
DefActSkuStock = 200 // 缺省活动库存
|
||
|
||
maxDiscount4SkuSecKill = 80
|
||
minDiscount4SkuDirectDown = 0
|
||
)
|
||
|
||
type ActOrderRuleParam struct {
|
||
SalePrice int64 `orm:"" json:"salePrice"` // 满的价格
|
||
DeductPrice int64 `orm:"" json:"deductPrice"` // 减的价格
|
||
}
|
||
|
||
type ActStoreSkuParam struct {
|
||
model.ActStoreSku
|
||
|
||
ActualActPrice int64 `json:"actualActPrice,omitempty"` // 单品级活动用,创建活动时商品的活动价格
|
||
VendorPrice int64 `json:"vendorPrice,omitempty"` // 创建活动时的平台价格
|
||
ErrMsg string `json:"errMsg,omitempty"`
|
||
}
|
||
|
||
type ActDetail struct {
|
||
model.Act2
|
||
}
|
||
|
||
type tPreCreateActVendorInfo struct {
|
||
VendorID int
|
||
|
||
VendorPrice int64 `orm:"" json:"vendorPrice"` // 单品级活动用,创建活动时商品的原始平台价
|
||
ActualActPrice int64 `orm:"" json:"actualActPrice"` // 单品级活动用,创建活动时商品的活动价格
|
||
}
|
||
|
||
type tPreCreateActStoreSku struct {
|
||
model.ActStoreSku
|
||
VendorInfoList []*tPreCreateActVendorInfo `json:"vendorInfoList"`
|
||
}
|
||
|
||
type tPreCreateActInfo struct {
|
||
model.Act
|
||
|
||
ValidVendorIDs []int
|
||
ActStoreSku []*tPreCreateActStoreSku `json:"actStoreSku"`
|
||
}
|
||
|
||
type ActManager struct {
|
||
}
|
||
|
||
var (
|
||
FixedActManager *ActManager
|
||
)
|
||
|
||
func init() {
|
||
FixedActManager = &ActManager{}
|
||
partner.InitActManager(FixedActManager)
|
||
}
|
||
|
||
func getVendorPriceFromStoreSkuBind(bind *model.StoreSkuBind, vendorID int) (vendorPrice int) {
|
||
switch vendorID {
|
||
case model.VendorIDJD:
|
||
vendorPrice = bind.JdPrice
|
||
case model.VendorIDMTWM:
|
||
vendorPrice = bind.MtwmPrice
|
||
case model.VendorIDEBAI:
|
||
vendorPrice = bind.EbaiPrice
|
||
}
|
||
return vendorPrice
|
||
}
|
||
|
||
func ActStoreSkuParam2Model(ctx *jxcontext.Context, db *dao.DaoDB, act *model.Act, vendorIDs []int, actStoreSku []*ActStoreSkuParam) (validVendorIDs []int, actStoreSkuList []*model.ActStoreSku, actStoreSkuMapList []*model.ActStoreSkuMap, err error) {
|
||
wholeValidVendorMap := make(map[int]int)
|
||
if len(actStoreSku) > 0 {
|
||
storeIDMap := make(map[int]int)
|
||
skuIDMap := make(map[int]int)
|
||
storeSkuParamMap := make(map[int][]*ActStoreSkuParam)
|
||
var wrongSkuList []*ActStoreSkuParam
|
||
for _, v := range actStoreSku {
|
||
if act.Type == model.ActSkuFake && v.EarningPrice == 0 {
|
||
wrongSkuList = append(wrongSkuList, v)
|
||
} else {
|
||
storeIDMap[v.StoreID] = 1
|
||
skuIDMap[v.SkuID] = 1
|
||
storeSkuParamMap[v.StoreID] = append(storeSkuParamMap[v.StoreID], v)
|
||
}
|
||
}
|
||
if len(wrongSkuList) > 0 {
|
||
return nil, nil, nil, jsonerr.New(wrongSkuList, model.ErrCodeJsonActEarningPriceIsZero)
|
||
}
|
||
storeIDs := jxutils.IntMap2List(storeIDMap)
|
||
skuIDs := jxutils.IntMap2List(skuIDMap)
|
||
// 判断活动是否重叠的检查,当前忽略京东平台及所有结算信息
|
||
if !(len(vendorIDs) == 1 && vendorIDs[0] == model.VendorIDJD || act.Type == model.ActSkuFake) {
|
||
effectActStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, vendorIDs, storeIDs, skuIDs, act.BeginAt, act.EndAt)
|
||
if err != nil {
|
||
globals.SugarLogger.Errorf("updateActPrice4StoreSkuNameNew can not get sku promotion info for error:%v", err)
|
||
return nil, nil, nil, err
|
||
}
|
||
if len(effectActStoreSkuList) > 0 {
|
||
return nil, nil, nil, jsonerr.New(effectActStoreSkuList, model.ErrCodeJsonActSkuConflict)
|
||
}
|
||
}
|
||
|
||
storeSkuList, err2 := dao.GetStoresSkusInfo(db, storeIDs, skuIDs)
|
||
if err = err2; err != nil {
|
||
return nil, nil, nil, err
|
||
}
|
||
storeSkuMap := make(map[int64]*model.StoreSkuBind)
|
||
for _, v := range storeSkuList {
|
||
storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] = v
|
||
}
|
||
|
||
for storeID, oneStoreSkuParam := range storeSkuParamMap {
|
||
validVendorMap := make(map[int]int)
|
||
validSkuMap := make(map[int]int)
|
||
for _, vendorID := range vendorIDs {
|
||
storeDetail, err2 := dao.GetStoreDetail(db, storeID, vendorID)
|
||
if err = err2; err == nil {
|
||
if storeDetail.IsSync != 0 && storeDetail.Status != model.StoreStatusDisabled && storeDetail.VendorStatus != model.StoreStatusDisabled {
|
||
for _, v := range oneStoreSkuParam {
|
||
validVendorMap[vendorID] = 1
|
||
validSkuMap[v.SkuID] = 1
|
||
v.ActID = act.ID
|
||
actSkuMap := &model.ActStoreSkuMap{
|
||
ActID: act.ID,
|
||
StoreID: storeID,
|
||
SkuID: v.SkuID,
|
||
VendorID: vendorID,
|
||
}
|
||
v.OriginalPrice = actSkuMap.VendorPrice
|
||
storeSkuInfo := storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)]
|
||
if storeSkuInfo != nil {
|
||
jxPrice := storeSkuInfo.Price
|
||
actSkuMap.VendorPrice = int64(getVendorPriceFromStoreSkuBind(storeSkuInfo, vendorID))
|
||
v.OriginalPrice = int64(jxPrice)
|
||
v.OriginalPrice = actSkuMap.VendorPrice // 暂时返回平台价
|
||
}
|
||
var err2 error
|
||
if act.Type != model.ActSkuFake { // 非结算,要计算实际活动价格
|
||
if storeSkuInfo == nil {
|
||
v.ErrMsg = fmt.Sprintf("门店:%d没有关注商品:%d", v.StoreID, v.SkuID)
|
||
wrongSkuList = append(wrongSkuList, v)
|
||
continue
|
||
}
|
||
actSkuMap.SyncStatus = model.SyncFlagNewMask
|
||
if v.ActPrice != 0 {
|
||
actSkuMap.ActualActPrice = v.ActPrice
|
||
} else {
|
||
percentage := act.PricePercentage
|
||
if v.PricePercentage != 0 {
|
||
percentage = v.PricePercentage
|
||
}
|
||
actSkuMap.ActualActPrice = int64(jxutils.CaculateSkuVendorPrice(int(actSkuMap.VendorPrice), percentage, 0))
|
||
if actSkuMap.ActualActPrice > 10 {
|
||
actSkuMap.ActualActPrice = int64(math.Floor(float64(actSkuMap.ActualActPrice)/10) * 10)
|
||
}
|
||
}
|
||
if actSkuMap.ActualActPrice <= 0 {
|
||
actSkuMap.ActualActPrice = 1
|
||
}
|
||
if err2 = checkDiscountValidation(act.Type, float64(actSkuMap.ActualActPrice)*100/float64(actSkuMap.VendorPrice)); err2 != nil {
|
||
v.ErrMsg = err2.Error()
|
||
v.ActualActPrice = actSkuMap.ActualActPrice
|
||
v.VendorPrice = actSkuMap.VendorPrice
|
||
wrongSkuList = append(wrongSkuList, v)
|
||
}
|
||
}
|
||
if err2 == nil {
|
||
dao.WrapAddIDCULDEntity(actSkuMap, ctx.GetUserName())
|
||
actStoreSkuMapList = append(actStoreSkuMapList, actSkuMap)
|
||
}
|
||
}
|
||
wholeValidVendorMap[vendorID] = 1
|
||
}
|
||
} else if !dao.IsNoRowsError(err) {
|
||
return nil, nil, nil, err
|
||
} else {
|
||
err = nil
|
||
}
|
||
}
|
||
if len(wrongSkuList) == 0 {
|
||
for _, v := range oneStoreSkuParam {
|
||
if validSkuMap[v.SkuID] == 1 { // todo 这里是否需要判断
|
||
storeSku := &v.ActStoreSku
|
||
dao.WrapAddIDCULDEntity(storeSku, ctx.GetUserName())
|
||
actStoreSkuList = append(actStoreSkuList, storeSku)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if len(wrongSkuList) > 0 {
|
||
return nil, nil, nil, jsonerr.New(wrongSkuList, model.ErrCodeJsonActPriceTooLarger)
|
||
}
|
||
}
|
||
return jxutils.IntMap2List(wholeValidVendorMap), actStoreSkuList, actStoreSkuMapList, err
|
||
}
|
||
|
||
func addActStoreSkuBind(ctx *jxcontext.Context, db *dao.DaoDB, actStoreSkuList []*model.ActStoreSku, actStoreSkuMapList []*model.ActStoreSkuMap) (err error) {
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
dao.Rollback(db)
|
||
panic(r)
|
||
}
|
||
}()
|
||
|
||
storeSkuMap := make(map[int64]int)
|
||
for _, v := range actStoreSkuList {
|
||
if v.Stock == 0 {
|
||
v.Stock = DefActSkuStock
|
||
}
|
||
err = dao.CreateEntity(db, v)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return err
|
||
}
|
||
storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] = v.ID
|
||
}
|
||
for _, v := range actStoreSkuMapList {
|
||
v.BindID = storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)]
|
||
}
|
||
|
||
if len(actStoreSkuMapList) > 0 {
|
||
err = dao.CreateMultiEntities(db, actStoreSkuMapList)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return err
|
||
}
|
||
}
|
||
dao.Commit(db)
|
||
return err
|
||
}
|
||
|
||
func AddActStoreSkuBind(ctx *jxcontext.Context, db *dao.DaoDB, actID int, actStoreSku []*ActStoreSkuParam) (err error) {
|
||
actMap, err := dao.GetActVendorInfo(db, actID, nil)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
vendorIDs := partner.GetVendorIDsFromActMap(actMap)
|
||
|
||
var act *model.Act
|
||
if len(vendorIDs) > 0 {
|
||
act = &actMap[vendorIDs[0]].Act
|
||
} else {
|
||
act = &model.Act{}
|
||
act.ID = actID
|
||
if err = dao.GetEntity(db, act); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
if act.Status != model.ActStatusCreated || time.Now().Sub(act.EndAt) > 0 {
|
||
return fmt.Errorf("当前活动状态:%s不能进行此操作,或已过期", model.ActStatusName[act.Status])
|
||
}
|
||
|
||
_, actStoreSkuList, actStoreSkuMapList, err := ActStoreSkuParam2Model(ctx, db, act, vendorIDs, actStoreSku)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
if err = addActStoreSkuBind(ctx, db, actStoreSkuList, actStoreSkuMapList); err != nil {
|
||
return err
|
||
}
|
||
if act.Type != model.ActSkuFake {
|
||
for _, act := range actMap {
|
||
if _, err = dao.UpdateEntityLogically(db, partner.Act2ActMap(act),
|
||
map[string]interface{}{
|
||
model.FieldSyncStatus: act.SyncStatus | model.SyncFlagModifiedMask,
|
||
}, ctx.GetUserName(), nil); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
dao.Commit(db)
|
||
return err
|
||
}
|
||
|
||
func checkDiscountValidation(actType int, pricePercentage float64) (err error) {
|
||
pricePercentageMin := int(math.Floor(pricePercentage))
|
||
pricePercentageMax := int(math.Ceil(pricePercentage))
|
||
if actType == model.ActSkuDirectDown && (pricePercentageMin < minDiscount4SkuDirectDown || pricePercentageMax > 99) {
|
||
if pricePercentageMin < minDiscount4SkuDirectDown {
|
||
err = fmt.Errorf("%s活动折扣必须大于:%d", model.ActTypeName[actType], minDiscount4SkuDirectDown)
|
||
} else if pricePercentageMax > 99 {
|
||
err = fmt.Errorf("%s活动必须有折扣", model.ActTypeName[actType])
|
||
}
|
||
} else if actType == model.ActSkuSecKill && pricePercentageMax > maxDiscount4SkuSecKill {
|
||
err = fmt.Errorf("%s活动折扣必须小于:%d", model.ActTypeName[actType], maxDiscount4SkuSecKill)
|
||
}
|
||
return err
|
||
}
|
||
|
||
func checkActValidation(act *model.Act, vendorIDs []int) (err error) {
|
||
errList := errlist.New()
|
||
if utils.IsTimeZero(act.BeginAt) || utils.IsTimeZero(act.EndAt) {
|
||
errList.AddErr(fmt.Errorf("活动开始与结束时间必须指定"))
|
||
} else if act.EndAt.Sub(act.BeginAt) < 0 {
|
||
errList.AddErr(fmt.Errorf("活动开始时间必须小于活动结束时间"))
|
||
}
|
||
vendorIDMap := make(map[int]int)
|
||
for _, vendorID := range vendorIDs {
|
||
vendorIDMap[vendorID] = 1
|
||
}
|
||
|
||
if act.Type == model.ActSkuDirectDown || act.Type == model.ActSkuSecKill {
|
||
if act.PricePercentage == 0 {
|
||
errList.AddErr(fmt.Errorf("必须指定缺省活动折扣"))
|
||
} else if err = checkDiscountValidation(act.Type, float64(act.PricePercentage)); err != nil {
|
||
errList.AddErr(err)
|
||
} else if act.Type == model.ActSkuSecKill && vendorIDMap[model.VendorIDMTWM] == 1 {
|
||
errList.AddErr(fmt.Errorf("%s平台不支持%s活动", model.VendorChineseNames[model.VendorIDMTWM], model.ActTypeName[model.ActSkuSecKill]))
|
||
}
|
||
} else if act.Type == model.ActSkuFake {
|
||
|
||
} else {
|
||
errList.AddErr(fmt.Errorf("当前只支持%s与%s活动", model.ActTypeName[model.ActSkuDirectDown], model.ActTypeName[model.ActSkuSecKill]))
|
||
}
|
||
err = errList.GetErrListAsOne()
|
||
return err
|
||
}
|
||
|
||
func setActDefault(act *model.Act) {
|
||
if act.LimitCount == 0 {
|
||
act.LimitCount = 1 // 缺省限购一份,如果确定不限,明确给一个很大的值
|
||
}
|
||
if act.LimitUser == 0 {
|
||
act.LimitUser = 1
|
||
}
|
||
act.Status = model.ActStatusCreated
|
||
}
|
||
|
||
func PreCreateAct(ctx *jxcontext.Context, act *model.Act, vendorIDs []int, actRules []*ActOrderRuleParam, actStoreSku []*ActStoreSkuParam) (preCreateActInfo *tPreCreateActInfo, err error) {
|
||
if err = checkActValidation(act, vendorIDs); err != nil {
|
||
return nil, err
|
||
}
|
||
setActDefault(act)
|
||
|
||
db := dao.GetDB()
|
||
validVendorIDs, actStoreSkuList, actStoreSkuMapList, err := ActStoreSkuParam2Model(ctx, db, act, vendorIDs, actStoreSku)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if len(validVendorIDs) == 0 {
|
||
dao.Rollback(db)
|
||
return nil, fmt.Errorf("没有一个合法平台可以创建活动")
|
||
}
|
||
|
||
preCreateActInfo = &tPreCreateActInfo{
|
||
ValidVendorIDs: validVendorIDs,
|
||
}
|
||
storeSkuMap := make(map[int64]*tPreCreateActStoreSku)
|
||
for _, v := range actStoreSkuList {
|
||
tmp := &tPreCreateActStoreSku{
|
||
ActStoreSku: *v,
|
||
}
|
||
storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)] = tmp
|
||
preCreateActInfo.ActStoreSku = append(preCreateActInfo.ActStoreSku, tmp)
|
||
}
|
||
|
||
for _, v := range actStoreSkuMapList {
|
||
index := jxutils.Combine2Int(v.StoreID, v.SkuID)
|
||
storeSkuMap[index].VendorInfoList = append(storeSkuMap[index].VendorInfoList, &tPreCreateActVendorInfo{
|
||
VendorID: v.VendorID,
|
||
VendorPrice: v.VendorPrice,
|
||
ActualActPrice: v.ActualActPrice,
|
||
})
|
||
}
|
||
return preCreateActInfo, nil
|
||
}
|
||
|
||
func CreateAct(ctx *jxcontext.Context, act *model.Act, vendorIDs []int, actRules []*ActOrderRuleParam, actStoreSku []*ActStoreSkuParam, isAsync bool) (hint string, err error) {
|
||
if err = checkActValidation(act, vendorIDs); err != nil {
|
||
return "", err
|
||
}
|
||
act.VendorMask = model.GetVendorMask(vendorIDs...)
|
||
setActDefault(act)
|
||
|
||
db := dao.GetDB()
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
dao.Rollback(db)
|
||
panic(r)
|
||
}
|
||
}()
|
||
dao.WrapAddIDCULDEntity(act, ctx.GetUserName())
|
||
err = dao.CreateEntity(db, act)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return "", err
|
||
}
|
||
|
||
validVendorIDs, actStoreSkuList, actStoreSkuMapList, err := ActStoreSkuParam2Model(ctx, db, act, vendorIDs, actStoreSku)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return "", err
|
||
}
|
||
if len(validVendorIDs) == 0 {
|
||
dao.Rollback(db)
|
||
return "", fmt.Errorf("没有一个合法平台可以创建活动")
|
||
}
|
||
|
||
var actMapList []*model.ActMap
|
||
for _, vendorID := range validVendorIDs {
|
||
actMap := &model.ActMap{
|
||
ActID: act.ID,
|
||
VendorID: vendorID,
|
||
|
||
SyncStatus: model.SyncFlagNewMask,
|
||
}
|
||
if act.Type == model.ActSkuFake {
|
||
actMap.SyncStatus = 0
|
||
}
|
||
dao.WrapAddIDCULDEntity(actMap, ctx.GetUserName())
|
||
actMapList = append(actMapList, actMap)
|
||
}
|
||
if len(actMapList) > 0 {
|
||
err = dao.CreateMultiEntities(db, actMapList)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return "", err
|
||
}
|
||
}
|
||
|
||
if err = addActStoreSkuBind(ctx, db, actStoreSkuList, actStoreSkuMapList); err != nil {
|
||
dao.Rollback(db)
|
||
return "", err
|
||
}
|
||
dao.Commit(db)
|
||
|
||
hint, err = SyncAct(ctx, nil, act.ID, nil, isAsync)
|
||
if !isAsync {
|
||
hint = utils.Int2Str(act.ID)
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func vendorActInfo2Model(ctx *jxcontext.Context, db *dao.DaoDB, act2 *model.Act2, actStoreSku []*model.ActStoreSku2) (actStoreSkuList []*model.ActStoreSku, actStoreSkuMapList []*model.ActStoreSkuMap, err error) {
|
||
vendorStoreIDMap := make(map[string]int)
|
||
vendorSkuIDMap := make(map[string]int)
|
||
for _, v := range actStoreSku {
|
||
vendorStoreIDMap[v.VendorStoreID] = 1
|
||
vendorSkuIDMap[v.VendorSkuID] = 1
|
||
}
|
||
// globals.SugarLogger.Debug(utils.Format4Output(vendorStoreIDMap, false))
|
||
// globals.SugarLogger.Debug(utils.Format4Output(vendorSkuIDMap, false))
|
||
|
||
vendorID := act2.VendorID
|
||
storeSkuList, err2 := dao.GetStoresSkusInfoByVendorInfo(db, vendorID, jxutils.StringMap2List(vendorStoreIDMap), jxutils.StringMap2List(vendorSkuIDMap))
|
||
if err = err2; err != nil {
|
||
return nil, nil, err
|
||
}
|
||
storeSkuMap := make(map[string]*dao.StoreSkuBindWithVendorInfo)
|
||
for _, v := range storeSkuList {
|
||
storeSkuMap[v.VendorStoreID+"/"+v.VendorSkuID] = v
|
||
}
|
||
storeSkuMap2 := make(map[int64]int)
|
||
for _, v := range actStoreSku {
|
||
if storeSkuInfo := storeSkuMap[v.VendorStoreID+"/"+v.VendorSkuID]; storeSkuInfo != nil {
|
||
index := jxutils.Combine2Int(storeSkuInfo.StoreID, storeSkuInfo.SkuID)
|
||
if storeSkuMap2[index] == 0 {
|
||
storeSkuMap2[index] = 1
|
||
actSku := &model.ActStoreSku{
|
||
ActID: act2.ID,
|
||
StoreID: storeSkuInfo.StoreID,
|
||
SkuID: storeSkuInfo.SkuID,
|
||
|
||
Stock: v.Stock,
|
||
ActPrice: v.ActualActPrice,
|
||
OriginalPrice: int64(storeSkuInfo.Price),
|
||
}
|
||
dao.WrapAddIDCULDEntity(actSku, ctx.GetUserName())
|
||
actStoreSkuList = append(actStoreSkuList, actSku)
|
||
|
||
actSkuMap := &model.ActStoreSkuMap{
|
||
ActID: act2.ID,
|
||
VendorActID: act2.VendorActID,
|
||
StoreID: storeSkuInfo.StoreID,
|
||
SkuID: storeSkuInfo.SkuID,
|
||
VendorID: vendorID,
|
||
|
||
SyncStatus: 0,
|
||
VendorPrice: 0,
|
||
ActualActPrice: v.ActualActPrice,
|
||
}
|
||
dao.WrapAddIDCULDEntity(actSkuMap, ctx.GetUserName())
|
||
actStoreSkuMapList = append(actStoreSkuMapList, actSkuMap)
|
||
}
|
||
}
|
||
}
|
||
return actStoreSkuList, actStoreSkuMapList, err
|
||
}
|
||
|
||
func (a *ActManager) CreateActFromVendor(ctx *jxcontext.Context, act2 *model.Act2, actStoreSku []*model.ActStoreSku2) (actID int, err error) {
|
||
globals.SugarLogger.Debugf("CreateActFromVendor vendorID:%d, vendorActID:%s", act2.VendorID, act2.VendorActID)
|
||
db := dao.GetDB()
|
||
return createActFromVendor(ctx, db, act2, actStoreSku)
|
||
}
|
||
|
||
func createActFromVendor(ctx *jxcontext.Context, db *dao.DaoDB, act2 *model.Act2, actStoreSku []*model.ActStoreSku2) (actID int, err error) {
|
||
actMap := &model.ActMap{
|
||
VendorID: act2.VendorID,
|
||
VendorActID: act2.VendorActID,
|
||
SyncStatus: 0,
|
||
}
|
||
dao.WrapAddIDCULDEntity(actMap, ctx.GetUserName())
|
||
if actMap.VendorActID != "" {
|
||
if err = dao.GetEntity(db, actMap, model.FieldVendorActID, model.FieldVendorID, model.FieldDeletedAt); err == nil {
|
||
return actMap.ActID, nil
|
||
} else if !dao.IsNoRowsError(err) {
|
||
return 0, err
|
||
}
|
||
err = nil
|
||
}
|
||
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
dao.Rollback(db)
|
||
panic(r)
|
||
}
|
||
}()
|
||
act := &act2.Act
|
||
act.VendorMask = model.GetVendorMask(act2.VendorID)
|
||
dao.WrapAddIDCULDEntity(act, ctx.GetUserName())
|
||
err = dao.CreateEntity(db, act)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return 0, err
|
||
}
|
||
|
||
actMap.ActID = act.ID
|
||
err = dao.CreateEntity(db, actMap)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return 0, err
|
||
}
|
||
actStoreSkuList, actStoreSkuMapList, err := vendorActInfo2Model(ctx, db, act2, actStoreSku)
|
||
if err != nil {
|
||
dao.Rollback(db)
|
||
return 0, err
|
||
}
|
||
if err = addActStoreSkuBind(ctx, db, actStoreSkuList, actStoreSkuMapList); err != nil {
|
||
dao.Rollback(db)
|
||
return 0, err
|
||
}
|
||
dao.Commit(db)
|
||
|
||
return act.ID, nil
|
||
}
|
||
|
||
func (a *ActManager) IsVendorActExist(ctx *jxcontext.Context, vendorActID string, vendorID int) (isExist bool) {
|
||
db := dao.GetDB()
|
||
actMap := &model.ActMap{
|
||
VendorActID: vendorActID,
|
||
VendorID: vendorID,
|
||
}
|
||
actMap.DeletedAt = utils.DefaultTimeValue
|
||
if err := dao.GetEntity(db, actMap, "VendorActID", "VendorID", "DeletedAt"); err == nil {
|
||
isExist = true
|
||
}
|
||
return isExist
|
||
}
|
||
|
||
func QueryActs(ctx *jxcontext.Context, actID int, offset, pageSize int, syncStatus int, keyword string, vendorID int, statusList, actTypeList, createTypeList []int, storeID, skuID, cityCode int, beginAt, endAt, createdAtFrom, createdAtTo time.Time) (pagedInfo *dao.PagedActListInfo, err error) {
|
||
return dao.QueryActs(dao.GetDB(), actID, offset, pageSize, syncStatus, keyword, vendorID, statusList, actTypeList, createTypeList, storeID, skuID, cityCode, beginAt, endAt, createdAtFrom, createdAtTo)
|
||
}
|
||
|
||
func GetActStoreSkuInfo(ctx *jxcontext.Context, actID int, vendorIDs []int, keyword string, offset, pageSize int) (retVal interface{}, err error) {
|
||
db := dao.GetDB()
|
||
totalCount, actStoreSkuList, err := dao.GetActStoreSkuVendorList(db, actID, vendorIDs, nil, nil, keyword, offset, pageSize)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
for _, v := range actStoreSkuList {
|
||
v.SkuName = jxutils.ComposeSkuName(v.Prefix, v.SkuNameName, v.Comment, v.Unit, v.SpecQuality, v.SpecUnit, 0)
|
||
}
|
||
if pageSize > 0 && pageSize != model.UnlimitedPageSize {
|
||
pagedInfo := &model.PagedInfo{
|
||
TotalCount: totalCount,
|
||
Data: actStoreSkuList,
|
||
}
|
||
retVal = pagedInfo
|
||
} else {
|
||
retVal = actStoreSkuList
|
||
}
|
||
return retVal, err
|
||
}
|
||
|
||
func CancelAct(ctx *jxcontext.Context, actID int) (err error) {
|
||
db := dao.GetDB()
|
||
if _, err = DeleteActStoreSkuBind(ctx, db, actID, nil); err != nil {
|
||
return err
|
||
}
|
||
_, err = SyncAct(ctx, nil, actID, nil, false)
|
||
return err
|
||
}
|
||
|
||
// actStoreSkuParam为空,不会删除act_store_sku,但会删除act_store_sku_map
|
||
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 len(actMap) == 0 {
|
||
return 0, fmt.Errorf("找不到活动:%d,或已被取消", actID)
|
||
}
|
||
if actMap[0].Status != model.ActStatusCreated {
|
||
// 如果不是正常状态直接跳过
|
||
return 0, nil
|
||
}
|
||
|
||
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 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 {
|
||
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
|
||
}
|
||
|
||
// todo 当前逻辑要求传入活动的全部SKU信息(以便低层做一些判断,比如全部删除时要取消,所以暂时删除storeIDs与skuIDs这两个参数
|
||
func SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, actID int, vendorIDs /*, storeIDs, skuIDs */ []int, isAsync bool) (hint string, err error) {
|
||
db := dao.GetDB()
|
||
actMap, err := dao.GetActVendorInfo(db, actID, vendorIDs)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, nil, nil, nil)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
if vendorIDs == nil {
|
||
vendorIDs = partner.GetVendorIDsFromActMap(actMap)
|
||
}
|
||
if len(vendorIDs) == 0 || actMap[vendorIDs[0]].Type == model.ActSkuFake {
|
||
return "", nil
|
||
}
|
||
task := tasksch.NewParallelTask("SyncAct", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
vendorID := batchItemList[0].(int)
|
||
if handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformActHandler); handler != nil {
|
||
tmpActMap := &model.ActMap{}
|
||
tmpActMap.ID = actMap[vendorID].MapID
|
||
if err = handler.SyncAct(ctx, nil, actMap[vendorID], nil, actStoreSkuMap[vendorID]); err == nil {
|
||
retVal = []int{1}
|
||
} else {
|
||
tmpActMap.Remark = utils.LimitUTF8StringLen(err.Error(), 1024)
|
||
}
|
||
// 保存最后一次同步错误信息
|
||
dao.UpdateEntity(db, tmpActMap, "Remark")
|
||
} else {
|
||
globals.SugarLogger.Warnf("SyncAct strange actID:%d, vendorID:%d", actID, vendorID)
|
||
}
|
||
return retVal, err
|
||
}, vendorIDs)
|
||
tasksch.HandleTask(task, parentTask, true).Run()
|
||
if !isAsync {
|
||
result, err2 := task.GetResult(0)
|
||
if err = err2; err == nil {
|
||
hint = utils.Int2Str(len(result))
|
||
}
|
||
} else {
|
||
hint = task.GetID()
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func RefreshPageActs(ctx *jxcontext.Context, vendorIDs []int, createdFrom time.Time, isAsync bool) (hint string, err error) {
|
||
task := tasksch.NewParallelTask("RefreshPageActs", nil, ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
vendorID := batchItemList[0].(int)
|
||
if handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformPageActHandler); handler != nil {
|
||
db := dao.GetDB()
|
||
actList, err2 := handler.GetPageActList(ctx, createdFrom)
|
||
globals.SugarLogger.Debug(utils.Format4Output(actList, false))
|
||
if err = err2; err != nil {
|
||
return nil, err
|
||
}
|
||
// actInfo, err2 := dao.QueryActs(db, 0, 0, -1, -1, "", vendorID, nil, []int{model.ActCreateTypeSpider},
|
||
// nil, 0, 0, 0, utils.DefaultTimeValue, utils.DefaultTimeValue, createdFrom, utils.DefaultTimeValue)
|
||
vendorActIDs, err2 := dao.GetExistVendorActIDs(db, vendorID)
|
||
if err = err2; err != nil {
|
||
return nil, err
|
||
}
|
||
localActMap := jxutils.StringList2Map(vendorActIDs)
|
||
// localActMap := make(map[string]*dao.ActVendorInfo)
|
||
// for _, v := range vendorActIDs {
|
||
// if v.VendorList[0].VendorActID != "" {
|
||
// localActMap[v.VendorList[0].VendorActID] = v
|
||
// }
|
||
// }
|
||
var needAddActList []*model.Act2
|
||
// var needUpdateActList []*model.Act
|
||
for _, v := range actList {
|
||
localAct := localActMap[v.VendorActID]
|
||
if localAct == 0 {
|
||
if v.Status == model.ActStatusCreated {
|
||
needAddActList = append(needAddActList, v)
|
||
}
|
||
}
|
||
// else if v.Status != localAct.Status {
|
||
// localAct.Status = v.Status
|
||
// needUpdateActList = append(needUpdateActList, &localAct.Act)
|
||
// }
|
||
}
|
||
subTask := tasksch.NewParallelTask("RefreshPageAct Sub", nil, ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
act2 := batchItemList[0].(*model.Act2)
|
||
actStoreSkuList, err := handler.GetPageActSkuList(ctx, act2.VendorActID)
|
||
if err == nil {
|
||
retVal = actStoreSkuList
|
||
}
|
||
return retVal, err
|
||
}, needAddActList)
|
||
tasksch.AddChild(task, subTask).Run()
|
||
|
||
skuList, err2 := subTask.GetResult(0)
|
||
if err = err2; err != nil {
|
||
return nil, err
|
||
}
|
||
needAddActSkuMap := make(map[string][]*model.ActStoreSku2)
|
||
for _, v := range skuList {
|
||
actStoreSku := v.(*model.ActStoreSku2)
|
||
needAddActSkuMap[actStoreSku.VendorActID] = append(needAddActSkuMap[actStoreSku.VendorActID], actStoreSku)
|
||
}
|
||
|
||
dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
|
||
for _, v := range needAddActList {
|
||
if len(needAddActSkuMap[v.VendorActID]) > 0 {
|
||
if _, err = createActFromVendor(ctx, db, v, needAddActSkuMap[v.VendorActID]); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
// for _, v := range needUpdateActList {
|
||
// if _, err = dao.UpdateEntity(db, v, model.FieldStatus); err != nil {
|
||
// return nil, err
|
||
// }
|
||
// }
|
||
dao.Commit(db)
|
||
}
|
||
return retVal, err
|
||
}, vendorIDs)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
if !isAsync {
|
||
hint = "1"
|
||
_, err = task.GetResult(0)
|
||
} else {
|
||
hint = task.GetID()
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
func DeleteSkusFromAct(ctx *jxcontext.Context, vendorID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
db := dao.GetDB()
|
||
actMap := make(map[int]*model.Act)
|
||
for _, skuID := range skuIDs {
|
||
pagedInfo, err2 := dao.QueryActs(db, 0, 0, -1, -1, "", vendorID, []int{model.ActStatusCreated}, []int{model.ActSkuDirectDown, model.ActSkuSecKill}, nil, 0, skuID, 0,
|
||
utils.DefaultTimeValue, utils.DefaultTimeValue, time.Now().Add(-24*30*3*time.Hour), utils.DefaultTimeValue)
|
||
if err = err2; err != nil {
|
||
return "", err
|
||
}
|
||
// globals.SugarLogger.Debug(utils.Format4Output(pagedInfo, false))
|
||
for _, v := range pagedInfo.Data {
|
||
actMap[v.Act.ID] = &v.Act
|
||
}
|
||
}
|
||
if len(actMap) == 0 {
|
||
return "", nil
|
||
}
|
||
skuIDMap := jxutils.IntList2Map(skuIDs)
|
||
var actIDList []int
|
||
for k := range actMap {
|
||
actIDList = append(actIDList, k)
|
||
}
|
||
task := tasksch.NewParallelTask("将SKU从所有活动中删除", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
actID := batchItemList[0].(int)
|
||
_, actStoreSkuList, err := dao.GetActStoreSkuVendorList(db, actID, []int{-1}, nil, skuIDs, "", 0, -1)
|
||
if err == nil {
|
||
// db := dao.GetDB()
|
||
var deleteList []*ActStoreSkuParam
|
||
for _, v := range actStoreSkuList {
|
||
if skuIDMap[v.SkuID] == 1 {
|
||
deleteList = append(deleteList, &ActStoreSkuParam{
|
||
ActStoreSku: model.ActStoreSku{
|
||
StoreID: v.StoreID,
|
||
SkuID: v.SkuID,
|
||
},
|
||
})
|
||
}
|
||
}
|
||
if len(deleteList) > 0 {
|
||
// globals.SugarLogger.Debug(utils.Format4Output(deleteList, false))
|
||
originSyncStatus, err2 := DeleteActStoreSkuBind(ctx, db, actID, deleteList)
|
||
if err = err2; err == nil && originSyncStatus == 0 {
|
||
if _, err = SyncAct(ctx, task, actID, nil, false); err == nil {
|
||
retVal = deleteList
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return retVal, err
|
||
}, actIDList)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
if isAsync {
|
||
hint = task.GetID()
|
||
} else {
|
||
resultList, err2 := task.GetResult(0)
|
||
if err = err2; err == nil {
|
||
hint = utils.Int2Str(len(resultList))
|
||
}
|
||
}
|
||
return hint, err
|
||
}
|