package act import ( "fmt" "time" "git.rosy.net.cn/baseapi/utils" "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/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 ( ActionTypeNA = 0 ) type ActOrderRuleParam struct { SalePrice int64 `orm:"" json:"salePrice"` // 满的价格 DeductPrice int64 `orm:"" json:"deductPrice"` // 减的价格 } type ActStoreSkuParam struct { Action int // -1删除,1修改,2新增 StoreID int `orm:"column(store_id)" json:"storeID"` SkuID int `orm:"column(sku_id)" json:"skuID"` PricePercentage int `orm:"" json:"pricePercentage"` // 单品级活动用,SKU级的价格比例,非0覆盖Act中的PricePercentage ActPrice int64 `orm:"" json:"actPrice"` // 单品级活动用,SKU级指定的价格,非0覆盖CustomPricePercentage与Act中的PricePercentage Stock int `orm:"" json:"stock"` // 订单级活动用 } type ActDetail struct { model.Act2 } func ActStoreSkuParam2Map(actStoreSku []*ActStoreSkuParam) (actStoreSkuMap map[int][]*ActStoreSkuParam) { if len(actStoreSku) > 0 { for _, v := range actStoreSku { actStoreSkuMap[v.StoreID] = append(actStoreSkuMap[v.StoreID], v) } } return actStoreSkuMap } func genStoreSkuMapKey(storeID, skuID int) int64 { return int64(storeID) + int64(skuID)*1000000 } func ActStoreSkuParam2Model(ctx *jxcontext.Context, act *model.Act, vendorIDs []int, actStoreSku []*ActStoreSkuParam) (actMapList []*model.ActMap, actStoreMapList []*model.ActStoreMap, actStoreSkuList []*model.ActStoreSku, actStoreSkuMapList []*model.ActStoreSkuMap, err error) { if len(actStoreSku) > 0 { storeIDMap := make(map[int]int) skuIDMap := make(map[int]int) storeSkuParamMap := make(map[int][]*ActStoreSkuParam) for _, v := range actStoreSku { storeIDMap[v.StoreID] = 1 skuIDMap[v.SkuID] = 1 storeSkuParamMap[v.StoreID] = append(storeSkuParamMap[v.StoreID], v) } db := dao.GetDB() storeSkuList, err2 := dao.GetStoresSkusInfo(db, jxutils.IntMap2List(storeIDMap), jxutils.IntMap2List(skuIDMap)) if err = err2; err != nil { return nil, nil, nil, nil, err } storeSkuMap := make(map[int64]*model.StoreSkuBind) for _, v := range storeSkuList { storeSkuMap[genStoreSkuMapKey(v.StoreID, v.SkuID)] = v } wholeValidVendorMap := make(map[int]int) 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 { for _, v := range oneStoreSkuParam { if storeSkuInfo := storeSkuMap[genStoreSkuMapKey(v.StoreID, v.SkuID)]; storeSkuInfo != nil { validVendorMap[vendorID] = 1 validSkuMap[v.SkuID] = 1 actSkuMap := &model.ActStoreSkuMap{ ActID: act.ID, StoreID: storeID, SkuID: v.SkuID, VendorID: vendorID, SyncStatus: model.SyncFlagNewMask, } if v.ActPrice != 0 { actSkuMap.ActualActPrice = v.ActPrice } else { percentage := act.PricePercentage if v.PricePercentage != 0 { percentage = v.PricePercentage } percentage = percentage * int(storeDetail.PricePercentage) / 100 actSkuMap.ActualActPrice = int64(jxutils.CaculateSkuVendorPrice(storeSkuInfo.Price, percentage, 0)) } dao.WrapAddIDCULDEntity(actSkuMap, ctx.GetUserName()) actStoreSkuMapList = append(actStoreSkuMapList, actSkuMap) } } } else if !dao.IsNoRowsError(err) { return nil, nil, nil, nil, err } else { err = nil } } for _, v := range oneStoreSkuParam { if validSkuMap[v.SkuID] == 1 { if storeSkuInfo := storeSkuMap[genStoreSkuMapKey(v.StoreID, v.SkuID)]; storeSkuInfo != nil { storeSku := &model.ActStoreSku{ ActID: act.ID, StoreID: v.StoreID, SkuID: v.SkuID, OriginalPrice: int64(storeSkuInfo.Price), PricePercentage: v.PricePercentage, ActPrice: v.ActPrice, Stock: v.Stock, } dao.WrapAddIDCULDEntity(storeSku, ctx.GetUserName()) actStoreSkuList = append(actStoreSkuList, storeSku) } } } for vendorID := range validVendorMap { wholeValidVendorMap[vendorID] = 1 actStoreMap := &model.ActStoreMap{ ActID: act.ID, StoreID: storeID, VendorID: vendorID, SyncStatus: model.SyncFlagNewMask, } dao.WrapAddIDCULDEntity(actStoreMap, ctx.GetUserName()) actStoreMapList = append(actStoreMapList, actStoreMap) } } for vendorID := range wholeValidVendorMap { actMap := &model.ActMap{ ActID: act.ID, VendorID: vendorID, SyncStatus: model.SyncFlagNewMask, } dao.WrapAddIDCULDEntity(actMap, ctx.GetUserName()) actMapList = append(actMapList, actMap) } } return actMapList, actStoreMapList, actStoreSkuList, actStoreSkuMapList, err } func CreateAct(ctx *jxcontext.Context, act *model.Act, vendorIDs []int, actRules []*ActOrderRuleParam, actStoreSku []*ActStoreSkuParam) (actID int, err error) { vendorIDMap := make(map[int]bool) for _, v := range vendorIDs { vendorIDMap[v] = true } db := dao.GetDB() dao.WrapAddIDCULDEntity(act, ctx.GetUserName()) dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() err = dao.CreateEntity(db, act) if err != nil { return 0, err } actMapList, actStoreMapList, actStoreSkuList, actStoreSkuMapList, err := ActStoreSkuParam2Model(ctx, act, vendorIDs, actStoreSku) if err != nil { return 0, err } isEmptyAct := true for _, list := range []interface{}{ actMapList, actStoreMapList, actStoreSkuList, actStoreSkuMapList, } { if len(utils.Interface2Slice(list)) > 0 { err = dao.CreateMultiEntities(db, list) if err != nil { dao.Rollback(db) return 0, err } isEmptyAct = false } } if isEmptyAct { dao.Rollback(db) return 0, fmt.Errorf("没有门店及SKU满足需求,空操作") } dao.Commit(db) actID = act.ID err = SyncAct(ctx, actID, nil, nil, nil) return actID, err } func QueryActs(ctx *jxcontext.Context, actID int, keyword string, statusList []int, actTypeList []int, storeID, skuID int, beginAt, endAt time.Time) (actList []*model.Act, err error) { return actList, err } func GetActDetail(ctx *jxcontext.Context, actID int) (actDetail *ActDetail, err error) { return actDetail, err } // func GetAcVendorInfo(ctx *jxcontext.Context, actID int) (err error) { // return err // } // func GetAcStoresVendorInfo(ctx *jxcontext.Context, actID int, storeIDs []int) (err error) { // return err // } // func GetAcStoresSkusVendorInfo(ctx *jxcontext.Context, actID int, storeIDs, skuIDs []int) (err error) { // return err // } func parseActStoreSkuParam(actStoreSku []*ActStoreSkuParam) { } func UpdateAct(ctx *jxcontext.Context, act *model.Act, actRules []*ActOrderRuleParam, actStoreSku []*ActStoreSkuParam) (err error) { return err } func CancelAct(ctx *jxcontext.Context, actID int) (err error) { db := dao.GetDB() act := &model.Act{} act.ID = actID if err = dao.GetEntity(db, act); err != nil { return err } dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() dao.UpdateEntityLogically(db, act, map[string]interface{}{ model.FieldStatus: model.ActStatusCanceled, }, ctx.GetUserName(), nil) _, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, &model.ActMap{}, nil, ctx.GetUserName(), map[string]interface{}{ model.FieldActID: actID, }, model.FieldSyncStatus, model.SyncFlagModifiedMask) if err == nil { dao.Commit(db) globals.SugarLogger.Debugf("CancelAct track:%s", ctx.GetTrackInfo()) err = SyncAct(ctx, actID, nil, nil, nil) } else { dao.Rollback(db) } return err } func SyncAct(ctx *jxcontext.Context, actID int, vendorIDs, storeIDs, skuIDs []int) (err error) { var actOrderRules []*model.ActOrderRule db := dao.GetDB() actMap, err := dao.GetActVendorInfo(db, actID, vendorIDs) if err != nil { return err } actStoreMap, err := dao.GetActStoreVendorInfo(db, actID, vendorIDs, storeIDs) if err != nil { return err } actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, vendorIDs, storeIDs, skuIDs) if err != nil { return err } var realVendorIDs []int for vendorID := range actMap { realVendorIDs = append(realVendorIDs, vendorID) } task := tasksch.NewParallelTask("SyncAct", nil, ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { vendorID := batchItemList[0].(int) handler := partner.GetPurchasePlatformFromVendorID(vendorID) if handler == nil { err = fmt.Errorf("不被支持的vendorID:%d", vendorID) } else { act := actMap[vendorID] actStore := actStoreMap[vendorID] actStoreSku := actStoreSkuMap[vendorID] // globals.SugarLogger.Debugf("%s", utils.Format4Output(act, false)) // globals.SugarLogger.Debugf("%s", utils.Format4Output(actStore, false)) // globals.SugarLogger.Debugf("%s", utils.Format4Output(actStoreSku, false)) if act != nil && actStore != nil && actStoreSku != nil { if model.IsSyncStatusNeedCreate(act.SyncStatus) { err = handler.CreateAct(ctx, task, act, actOrderRules, actStore, actStoreSku) } else if model.IsSyncStatusNeedUpdate(act.SyncStatus) { if act.Status == model.ActStatusCanceled { err = handler.CancelAct(ctx, task, act, actStore, actStoreSku) } else { // actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update := splitActStore(actStore) // err = handler.UpdateAct(ctx, task, act, actOrderRules, actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update, actStoreSku) } } if err == nil { actMap := &model.ActMap{} actMap.ID = act.MapID dao.UpdateEntityLogically(db, actMap, map[string]interface{}{ model.FieldSyncStatus: 0, model.FieldVendorActID: act.VendorActID, }, ctx.GetUserName(), nil) for _, v := range actStore { storeMap := model.ActStoreMap{} storeMap.ID = v.MapID dao.UpdateEntityLogically(db, storeMap, map[string]interface{}{ model.FieldSyncStatus: 0, model.FieldVendorActID: v.VendorActID, }, ctx.GetUserName(), nil) } for _, v := range actStoreSku { storeSkuMap := model.ActStoreSkuMap{} storeSkuMap.ID = v.MapID dao.UpdateEntityLogically(db, storeSkuMap, map[string]interface{}{ model.FieldSyncStatus: 0, model.FieldVendorActID: v.VendorActID, }, ctx.GetUserName(), nil) } } } } return nil, err }, realVendorIDs) tasksch.ManageTask(task).Run() _, err = task.GetResult(0) return err } func splitActStore(actStore []*model.ActStore2) (actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update []*model.ActStore2) { for _, v := range actStore { if model.IsSyncStatusNeedDelete(v.SyncStatus) { if !dao.IsVendorThingIDEmpty(v.VendorActID) { actStoreMap2Remove = append(actStoreMap2Remove, v) } } else if model.IsSyncStatusNeedCreate(v.SyncStatus) { actStoreMap2Add = append(actStoreMap2Add, v) } else if model.IsSyncStatusNeedUpdate(v.SyncStatus) { actStoreMap2Update = append(actStoreMap2Update, v) } } return actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update }