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 ( DefActSkuStock = 200 // 缺省活动库存 ) type ActOrderRuleParam struct { SalePrice int64 `orm:"" json:"salePrice"` // 满的价格 DeductPrice int64 `orm:"" json:"deductPrice"` // 减的价格 } type ActStoreSkuParam struct { model.ActStoreSku } type ActDetail struct { model.Act2 } type ActMapPureInfo struct { VendorID int `orm:"column(vendor_id)" json:"vendorID"` VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"` SyncStatus int `orm:"default(2)" json:"syncStatus"` } type ActVendorInfo struct { model.Act VendorList []*ActMapPureInfo } 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) for _, v := range actStoreSku { storeIDMap[v.StoreID] = 1 skuIDMap[v.SkuID] = 1 storeSkuParamMap[v.StoreID] = append(storeSkuParamMap[v.StoreID], v) } storeSkuList, err2 := dao.GetStoresSkusInfo(db, jxutils.IntMap2List(storeIDMap), jxutils.IntMap2List(skuIDMap)) 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 { for _, v := range oneStoreSkuParam { if storeSkuInfo := storeSkuMap[jxutils.Combine2Int(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) } } wholeValidVendorMap[vendorID] = 1 } else if !dao.IsNoRowsError(err) { return nil, nil, nil, err } else { err = nil } } for _, v := range oneStoreSkuParam { if validSkuMap[v.SkuID] == 1 { // todo 这里是否需要判断 if storeSkuInfo := storeSkuMap[jxutils.Combine2Int(v.StoreID, v.SkuID)]; storeSkuInfo != nil { storeSku := &v.ActStoreSku storeSku.ActID = act.ID storeSku.OriginalPrice = int64(storeSkuInfo.Price) dao.WrapAddIDCULDEntity(storeSku, ctx.GetUserName()) actStoreSkuList = append(actStoreSkuList, storeSku) } } } } } 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 { 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 } 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 CreateAct(ctx *jxcontext.Context, act *model.Act, vendorIDs []int, actRules []*ActOrderRuleParam, actStoreSku []*ActStoreSkuParam, isAsync bool) (hint string, err error) { db := dao.GetDB() dao.Begin(db) defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() if act.LimitCount == 0 { act.LimitCount = 1 // 缺省限购一份,如果确定不限,明确给一个很大的值 } act.Status = model.ActStatusCreated 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 { return "", err } var actMapList []*model.ActMap for _, vendorID := range validVendorIDs { actMap := &model.ActMap{ ActID: act.ID, VendorID: vendorID, SyncStatus: model.SyncFlagNewMask, } 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, nil, nil, isAsync) if !isAsync { hint = utils.Int2Str(act.ID) } return hint, err } func QueryActs(ctx *jxcontext.Context, actID int, offset, pageSize int, keyword string, statusList []int, actTypeList []int, storeID, skuID, cityCode int, beginAt, endAt, createdAtFrom, createdAtTo time.Time) (pagedInfo *dao.PagedActListInfo, err error) { return dao.QueryActs(dao.GetDB(), actID, offset, pageSize, keyword, statusList, actTypeList, storeID, skuID, cityCode, beginAt, endAt, createdAtFrom, createdAtTo) } func GetActVendorInfo(ctx *jxcontext.Context, actID int) (actVendorInfo *ActVendorInfo, err error) { db := dao.GetDB() actMap, err := dao.GetActVendorInfo(db, actID, nil) if err != nil { return nil, err } if len(actMap) == 0 { return nil, fmt.Errorf("不能找到活动:%d", actID) } actVendorInfo = &ActVendorInfo{} for vendorID, v := range actMap { if actVendorInfo.ID == 0 { actVendorInfo.Act = v.Act } actVendorInfo.VendorList = append(actVendorInfo.VendorList, &ActMapPureInfo{ VendorID: vendorID, SyncStatus: v.SyncStatus, VendorActID: v.VendorActID, }) } return actVendorInfo, err } func GetActStoreSkuInfo(ctx *jxcontext.Context, actID int, vendorIDs []int) (actStoreSkuList []*model.ActStoreSku2, err error) { db := dao.GetDB() actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, vendorIDs, nil, nil) if err != nil { return nil, err } if len(actStoreSkuMap) == 0 { return nil, fmt.Errorf("不能找到活动:%d", actID) } for _, v := range actStoreSkuMap { actStoreSkuList = append(actStoreSkuList, v...) } return actStoreSkuList, 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, nil, nil, false) return err } // actStoreSkuParam为空,不会删除act_store_sku,但会删除act_store_sku_map func DeleteActStoreSkuBind(ctx *jxcontext.Context, db *dao.DaoDB, actID int, actStoreSkuParam []*ActStoreSkuParam) (err error) { actMap, err := dao.GetActVendorInfo(db, actID, nil) if err != nil { return err } if len(actMap) == 0 { return fmt.Errorf("找不到活动:%d,或已被取消", actID) } actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, nil, nil, nil) if err != nil { return err } act := actMap[partner.GetVendorIDsFromActMap(actMap)[0]] if act.Status != model.ActStatusCreated { return 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 err } } isNeedCancelAct := true for vendorID, act := range actMap { isDeleteAll := true isDeleteAtLeastOne := false 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 _, err = dao.UpdateEntityLogically(db, partner.ActStoreSku2ActStoreSkuMap(actStoreSku), map[string]interface{}{ model.FieldSyncStatus: actStoreSku.SyncStatus | model.SyncFlagDeletedMask, }, ctx.GetUserName(), nil); err != nil { return err } isDeleteAtLeastOne = true } else { isNeedCancelAct = false isDeleteAll = false } } } if isDeleteAll || isDeleteAtLeastOne { syncStatus := model.SyncFlagModifiedMask if isDeleteAll { syncStatus = model.SyncFlagDeletedMask } syncStatus |= act.SyncStatus if _, err = dao.UpdateEntityLogically(db, partner.Act2ActMap(act), map[string]interface{}{ model.FieldSyncStatus: syncStatus, }, ctx.GetUserName(), nil); err != nil { return 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 err } } dao.Commit(db) return err } 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, storeIDs, skuIDs) if err != nil { return "", err } if vendorIDs == nil { vendorIDs = partner.GetVendorIDsFromActMap(actMap) } 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 { if err = handler.SyncAct(ctx, nil, actMap[vendorID], nil, actStoreSkuMap[vendorID]); err == nil { retVal = []int{1} } } 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 }