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 }