package shop import ( "bet24.com/log" "bet24.com/redis" "bet24.com/servers/common" "bet24.com/servers/coreservice/giftpack" "bet24.com/servers/coreservice/monthlycard" activityservice "bet24.com/servers/micros/activityservice/proto" badge "bet24.com/servers/micros/badge/proto" dotservice "bet24.com/servers/micros/dotservice/proto" giftservice "bet24.com/servers/micros/giftservice/proto" highlyprofitable "bet24.com/servers/micros/highly_profitable/proto" inventory "bet24.com/servers/micros/item_inventory/proto" item "bet24.com/servers/micros/item_inventory/proto" money "bet24.com/servers/micros/money/proto" notification "bet24.com/servers/micros/notification/proto" task "bet24.com/servers/micros/task/proto" userlabel "bet24.com/servers/micros/userlabel/proto" waterPool "bet24.com/servers/micros/waterpool/proto" //user "bet24.com/servers/micros/userservices/proto" "encoding/json" "fmt" "sort" "strconv" "strings" "sync" "time" vipservice "bet24.com/servers/micros/userservices/proto" ) type shopmgr struct { lock *sync.RWMutex //exchangeRateList []*exchangeRate firstChargeList []*Shop_Item shopList map[string]*Shop_Item } func newShopMgr() *shopmgr { obj := new(shopmgr) obj.lock = &sync.RWMutex{} obj.shopList = make(map[string]*Shop_Item) //obj.loadExchangeRate() obj.loadShopList() log.Debug("shop manager running") return obj } /* // 先加载汇率 func (this *shopmgr) loadExchangeRate() { list := getExchangeRate() if list == nil { log.Error("shopmgr.loadExchangeRate is empty ...") } this.lock.Lock() defer this.lock.Unlock() this.exchangeRateList = list } */ func (this *shopmgr) loadShopList() { time.AfterFunc(2*time.Minute, this.loadShopList) // 商城列表 list := getShopList() this.firstChargeList = []*Shop_Item{} this.lock.Lock() this.shopList = make(map[string]*Shop_Item) for _, v := range list { if v.Bonus > 0 { bonus := float64(v.Bonus) / 100 // 实际给的道具 for j := 0; j < len(v.Extra); j++ { v.Extra[j].Count = int(float64(v.Extra[j].Count) * bonus) } } this.shopList[v.ProductId] = v if v.ShopType == ShopType_FirstCharge { this.firstChargeList = append(this.firstChargeList, v) } } this.lock.Unlock() } func (this *shopmgr) getShopList(userId, shopType int) []*Shop_Item { var list []*Shop_Item isAllow := this.isFirstChargeAllow(userId) this.lock.RLock() for _, v := range this.shopList { if v.ShopType != shopType && shopType != 0 { continue } if v.ShopType == ShopType_FirstCharge && !isAllow { continue } // 苹果多渠道产品不下发 if PayType_RMB == v.PayType && strings.Contains(v.ProductId, "BL_") { continue } if v.ShopType == ShopType_FirstCharge { str, ret := redis.String_Get(fmt.Sprintf("%d:%s", userId, v.ProductId)) if ret && str != "" { v.Status = 2 } else { v.Status = 0 } } list = append(list, v) } this.lock.RUnlock() // changePrice带锁,所以需要在锁外处理 for k, v := range list { // list[k] = this.changePrice(userId, v) list[k] = this.getSavingPotAmount(userId, v) } sort.Slice(list, func(i, j int) bool { if list[i].ShopType == list[j].ShopType && list[i].ShopType == ShopType_Diamond { return list[i].Price < list[j].Price } return list[i].ProductId < list[j].ProductId }) return list } func (this *shopmgr) getUserPrice(userId int, price float64) float64 { return price /* uInfo := user.GetUserInfo(userId) currency := "" if uInfo != nil { currency = uInfo.Currency } return this.getLocalPrice(currency, price) */ } /* func (this *shopmgr) getLocalPrice(currency string, basePrice float64) float64 { if currency == "" { return basePrice } info := this.exchangeRateInfo(currency) if info == nil { return basePrice } return info.Rate * basePrice } */ func (this *shopmgr) getProduct(userId int, productId string) *Shop_Item { this.lock.RLock() si, ok := this.shopList[productId] this.lock.RUnlock() if !ok { return nil } //return si //return this.changePrice(userId, si) return this.getSavingPotAmount(userId, si) } // 获取存钱罐数据 func (this *shopmgr) getSavingPotAmount(userId int, shopItem *Shop_Item) *Shop_Item { if shopItem.PayType != PayType_RMB || shopItem.ShopType != ShopType_SavingPot { return shopItem } // 存钱罐 amount := activityservice.GetUserSavingPotBuyAmount(userId, shopItem.ProductId == "1300001") if amount <= 0 && shopItem.ProductId != "1300001" { return shopItem } items := make([]item.ItemPack, len(shopItem.Extra)) copy(items, shopItem.Extra) // 追加存钱罐 for i := 0; i < len(items); i++ { if items[i].ItemId != item.Item_Gold { continue } if shopItem.ProductId != "1300001" { items[i].Count = amount } else { items[i].Count += amount } break } cpyItem := &Shop_Item{ ProductId: shopItem.ProductId, ProductName: shopItem.ProductName, Price: shopItem.Price, ShowPrice: shopItem.ShowPrice, PayType: shopItem.PayType, ShopType: shopItem.ShopType, IsHot: shopItem.IsHot, Bonus: shopItem.Bonus, Extra: items, Status: shopItem.Status, Sort: shopItem.Sort, AnimationType: shopItem.AnimationType, UserType: shopItem.UserType, IsBottom: shopItem.IsBottom, } return cpyItem } /* func (this *shopmgr) changePrice(userId int, shopItem *Shop_Item) *Shop_Item { if userId <= 0 || shopItem.PayType != PayType_RMB { return shopItem } // 需要转换价格 // 获取 uInfo := user.GetUserInfo(userId) currency := "" if uInfo != nil { currency = uInfo.Currency } items := make([]item.ItemPack, len(shopItem.Extra)) copy(items, shopItem.Extra) cpyItem := &Shop_Item{ ProductId: shopItem.ProductId, ProductName: shopItem.ProductName, Price: shopItem.Price, ShowPrice: shopItem.ShowPrice, PayType: shopItem.PayType, ShopType: shopItem.ShopType, IsHot: shopItem.IsHot, Bonus: shopItem.Bonus, Extra: items, Status: shopItem.Status, /*Sort: shopItem.Sort, AnimationType: shopItem.AnimationType, UserType: shopItem.UserType, IsBottom: shopItem.IsBottom,* / } cpyItem.Price = this.getLocalPrice(currency, cpyItem.Price) cpyItem.ShowPrice = this.getLocalPrice(currency, cpyItem.ShowPrice) return cpyItem } */ func (this *shopmgr) exchangeInBulk(userId int, productIds []string) (int, string) { ret := 0 msg := "" totalDiamond := 0 var items []item.ItemPack totalGold := 0 for _, v := range productIds { product := this.getProduct(userId, v) if product == nil { msg = fmt.Sprintf("userId=%d Product信息(%s)Not Exist", userId, v) log.Error("shop.exchange %s ", msg) return ret, msg } if product.ShopType < ShopType_Gold || product.ShopType >= ShopType_Max { msg = fmt.Sprintf("userId=%d Product(%s) Invalid", userId, v) log.Error("shop.exchange %s", msg) return ret, msg } if product.PayType == PayType_Diamond { totalDiamond += int(product.Price) } else if product.PayType == PayType_Gold { totalGold += int(product.Price) } else { msg = fmt.Sprintf("userId=%d Product信息(%s)Invalid", userId, v) log.Error("shop.exchange %s ", msg) return ret, msg } items = append(items, product.Extra...) } items = item.GroupItems(items) remark := "批量兑换" //扣钻石 if totalDiamond > 0 { if money.ReduceChip(userId, totalDiamond, common.LOGTYPE_EXCHANGE_GOLD, "shop", "exchangeGoldInBulk", "") != 1 { msg = fmt.Sprintf("userId=%d not enough diamond need %d", userId, totalDiamond) log.Release("shop.exchangeInBulk %s ", msg) return ret, msg } } if totalGold > 0 { if !money.ReduceMoney(userId, totalGold, common.LOGTYPE_EXCHANGE_GOLD, "shop", "exchangeGoldInBulk", "") { msg = fmt.Sprintf("userId=%d not enough gold need %d", userId, totalGold) log.Release("shop.exchangeInBulk %s ", msg) if totalDiamond > 0 { money.GiveChip(userId, totalDiamond, common.LOGTYPE_EXCHANGE_GOLD, "shop", "exchangeGoldInBulk return", "") } return ret, msg } } //加道具 if success := inventory.AddItems(userId, items, remark, common.LOGTYPE_EXCHANGE_GOLD); !success { ret = 0 msg = fmt.Sprintf("exchange gold failure") log.Debug("shop.exchangeInBulk userId=%d product=%v %s,加道具失败", userId, items, msg) return ret, msg } d, _ := json.Marshal(items) notification.AddNotification(userId, notification.Notification_Exchange, string(d)) task.DoTaskAction(userId, task.TaskAction_exchange_item, 1, task.TaskScope{}) ret = 1 msg = "Success" return ret, msg } func (this *shopmgr) sendFirstChargeItem(userId int, productId string) (int, string) { key := fmt.Sprintf("%d:%s", userId, productId) data, success := redis.String_Get(key) if !success || data == "" { return 0, "" } var resp item.ItemFirstCharge err := json.Unmarshal([]byte(data), &resp) if err != nil { return 0, "" } nowDayIndex := common.GetNowDayIndex() diffDay := nowDayIndex - resp.BuyDayIndex if diffDay <= 0 { return 0, "" } var items []item.ItemPack for i := 0; i < len(resp.Items); i++ { if diffDay >= resp.Items[i].Day { items = append(items, resp.Items[i]) } } if len(items) == 0 { return 0, "" } count := item.GetItemExtraCount(items, item.Item_Chip) badge.DoAction(userId, badge.Action_Recharge, count, badge.Scope{}) //购买, 通知客户端 d, _ := json.Marshal(notification.NotificationRecharge{ RetCode: 0, Items: items, ProductId: productId, ShopType: resp.ShopType, BasePrice: resp.BasePrice, IsRefresh: diffDay >= 2, IsGift: false, }) inventory.AddItems(userId, items, "充值成功", common.LOGTYPE_SHOPBUY) notification.AddNotification(userId, notification.Notification_Recharge, string(d)) if diffDay >= 2 { redis.String_SetEx(key, "", 1) } else { var returnValue item.ItemFirstCharge returnValue.BasePrice = resp.BasePrice returnValue.BuyDayIndex = resp.BuyDayIndex returnValue.ProductId = resp.ProductId returnValue.ShopType = resp.ShopType for n := 0; n < len(resp.Items); n++ { if resp.Items[n].Day > 1 { returnValue.Items = append(returnValue.Items, resp.Items[n]) } } value, _ := json.Marshal(returnValue) redis.String_Set(key, string(value)) } return 1, "Success" } func (this *shopmgr) exchange(userId int, productId string) (int, string) { ret := 0 msg := "" product := this.getProduct(userId, productId) if product == nil { msg = fmt.Sprintf("userId=%d Product信息(%s)Not Exist", userId, productId) log.Error("shop.exchange %s ", msg) return ret, msg } if product.ShopType < ShopType_Gold || product.ShopType >= ShopType_Max { msg = fmt.Sprintf("userId=%d Product(%s) Invalid", userId, productId) log.Error("shop.exchange %s", msg) return ret, msg } if product.PayType != PayType_Diamond && product.PayType != PayType_Gold { msg = fmt.Sprintf("userId=%d Product信息(%s)Invalid", userId, productId) log.Error("shop.exchange %s ", msg) return ret, msg } remark := "钻石兑换" price := int(product.Price) if product.PayType == PayType_Gold { remark = "金币兑换" if !money.ReduceMoney(userId, price, common.LOGTYPE_EXCHANGE_GOLD, "shop", "exchangeGold", "") { msg = fmt.Sprintf("userId=%d not enough gold", userId) log.Release("shop.exchange %s ", msg) return ret, msg } // 徽章进度 badge.DoAction(userId, badge.Action_PropConsumeGold, price, badge.Scope{}) } else { //扣钻石 if money.ReduceChip(userId, price, common.LOGTYPE_EXCHANGE_GOLD, "shop", "exchangeGold", "") != 1 { msg = fmt.Sprintf("userId=%d not enough chip", userId) log.Release("shop.exchange %s ", msg) return ret, msg } } //加道具 if success := inventory.AddItems(userId, product.Extra, remark, common.LOGTYPE_EXCHANGE_GOLD); !success { ret = 0 msg = fmt.Sprintf("exchange gold failure") log.Debug("shop.exchange userId=%d product=%+v %s,加道具失败", userId, product, msg) return ret, msg } d, _ := json.Marshal(product.Extra) notification.AddNotification(userId, notification.Notification_Exchange, string(d)) task.DoTaskAction(userId, task.TaskAction_exchange_item, 1, task.TaskScope{}) ret = 1 msg = "Success" return ret, msg } func (this *shopmgr) recharge(userId int, productId string) (int, string) { ret, msg := 0, "购买失败" product := this.getProduct(userId, productId) if product == nil { msg = fmt.Sprintf("userId=%d, Product信息(%s)Not Exist", userId, productId) log.Error("shop.recharge %s ", msg) return ret, msg } log.Debug("shopmgr.recharge userId=%d productId=%s ==>%+v", userId, productId, product) if product.ShopType < ShopType_Gold || product.ShopType >= ShopType_Max { msg = fmt.Sprintf("userId=%d Product(%s) Invalid", userId, productId) log.Error("shop.recharge %s", msg) return ret, msg } if product.PayType != PayType_RMB { msg = fmt.Sprintf("Product信息(%s)不允许充值", productId) log.Error("shop.recharge 支付 PayType(%d), %s ", product.PayType, msg) return ret, msg } // 获取金币 _, amount := money.GetMoney(userId) //道具 var items []item.ItemPack switch product.ShopType { case ShopType_GrowthGift: // 购买新手礼包 this.sendNotification(userId, ret, productId, items, product, false) activityservice.BuyGiftPackage(userId, productId) return 1, "购买成功" case ShopType_VipPackage: // 购买vip礼包 this.sendNotification(userId, ret, productId, items, product, false) vipservice.BuyPackage(userId, productId) return 1, "购买成功" case ShopType_RechargeGift: //充值礼包 items = giftpack.BuyGiftPack(userId, productId) if items == nil { ret = 0 log.Debug("shop.recharge userId=%d product=%+v %s,购买礼包失败", userId, product, msg) return ret, msg } /*case ShopType_GrowthGift: //成长礼包 if ret, msg, items = giftpack.BuyGrowthPack(userId, productId); ret != 1 { ret = 0 log.Debug("shop.recharge userId=%d product=%+v %s,购买成长礼包失败", userId, product, msg) return ret, msg }*/ case ShopType_MonthlyCard: //购买月卡 if productId == monthlycard.Month_ProductId { if ret, items = monthlycard.BuyMonth(userId); ret != 1 { ret = 0 log.Debug("shop.recharge userId=%d product=%+v %s,购买月卡失败", userId, product, msg) return ret, msg } } else if productId == monthlycard.Week_ProductId { if ret, items = monthlycard.BuyWeek(userId); ret != 1 { ret = 0 log.Debug("shop.recharge userId=%d product=%+v %s,购买周卡失败", userId, product, msg) return ret, msg } } case ShopType_Diamond, ShopType_FirstCharge: // 钻石、首充礼包 if !this.isFirstChargeBuy(userId) && ShopType_FirstCharge == product.ShopType { return ret, msg } tempItems := []item.ItemPack{} if product.ShopType == ShopType_FirstCharge { for i := 0; i < len(product.Extra); i++ { if product.Extra[i].Day == 0 { tempItems = append(tempItems, product.Extra[i]) } } } else { tempItems = append(tempItems, product.Extra...) } // 徽章进度 count := item.GetItemExtraCount(tempItems, item.Item_Chip) badge.DoAction(userId, badge.Action_Recharge, count, badge.Scope{}) fallthrough default: if product.ShopType == ShopType_SavingPot { // 存钱罐 if product.Extra[0].Count <= 0 { return ret, msg } success := activityservice.SavingPotBuy(userId, product.ProductId == "1300001") if !success { return ret, msg } } else if product.ShopType == ShopType_HighlyProfitable { // 一本万利 highlyprofitable.ActivationHighlyProfitableNotification(userId) } remark := "充值成功" if product.ShopType == ShopType_FirstCharge { var firstCharge item.ItemFirstCharge firstCharge.BuyDayIndex = common.GetNowDayIndex() firstCharge.BasePrice = product.Price firstCharge.ProductId = product.ProductId firstCharge.ShopType = ShopType_FirstCharge key := fmt.Sprintf("%d:%s", userId, productId) for i := 0; i < len(product.Extra); i++ { if product.Extra[i].Day == 0 { items = append(items, product.Extra[i]) } else { firstCharge.Items = append(firstCharge.Items, product.Extra[i]) } } if len(firstCharge.Items) > 0 { value, _ := json.Marshal(firstCharge) redis.String_Set(key, string(value)) } } else { items = append(items, product.Extra...) } isGift := false // 如果是赠送礼物,则由礼物系统发放道具给对方 if !giftservice.CheckGiftCharge(userId, productId) { //加道具 if success := inventory.AddItems(userId, items, remark, common.LOGTYPE_SHOPBUY); !success { ret = 0 msg = fmt.Sprintf("充值失败") log.Debug("shop.recharge userId=%d product=%+v %s,充值钻石失败", userId, product, msg) return ret, msg } } else { log.Release("giftservice.CheckGiftCharge %d,%s", userId, productId) isGift = true } this.sendNotification(userId, ret, productId, items, product, isGift) } go func() { price := int(product.Price + 0.5) // 充值触发 payTrigger(userId, productId, product.ShopType, price) //user.AddPoint(userId, price) // 新版vip添加点数,触发升级 vipservice.AddVipPoint(userId, price) task.DoTaskAction(userId, task.TaskAction_pay, price, task.TaskScope{}) // 触发用户标签 userlabel.TriggerEvent(userId, userlabel.Type_Charge, userlabel.Scope{ GoldAmount: amount, PayPrice: product.Price, IsDiscount: product.ShowPrice > product.Price, Num: 1, }) // 打点统计 dotservice.AddDot(userId, dotservice.DotScope{ Scene: dotservice.Scene_Shop, Action: dotservice.Action_Complete, Extra: productId, }) // 等级礼包 if product.ShopType == ShopType_LevelRewards { activityservice.UpdateUserInfoToLevelRewards(userId) } // 加个人奖池 waterPool.GrantUserNewWaterPool(userId, price*10000, "充值") }() ret = 1 msg = "购买成功" return ret, msg } // 发送通知 func (this *shopmgr) sendNotification(userId, ret int, productId string, items []item.ItemPack, product *Shop_Item, isGift bool) { //购买, 通知客户端 d, _ := json.Marshal(notification.NotificationRecharge{ RetCode: ret, Items: items, ProductId: productId, ShopType: product.ShopType, BasePrice: product.Price, IsRefresh: product.Bonus > 0 || product.ShopType == ShopType_SavingPot, IsGift: isGift, }) notification.AddNotification(userId, notification.Notification_Recharge, string(d)) } func isDouble(userId int, productId string) bool { fp := getFirstPurchase(userId) for _, v := range fp { if v.productId == productId { return v.value } } return false } func (this *shopmgr) isFirstChargeBuy(userId int) bool { if len(this.firstChargeList) == 0 { return false } fp := getFirstPurchase(userId) for _, v := range fp { if v.value { // 没有购买过 continue } // 已经购买过,并且属于首充ID for _, v2 := range this.firstChargeList { if v.productId == v2.ProductId { return false } } } return true } func (this *shopmgr) isFirstChargeAllow(userId int) bool { if len(this.firstChargeList) == 0 { return false } fp := getFirstPurchase(userId) for _, v := range fp { if v.value { // 没有购买过 continue } // 已经购买过,并且属于首充ID for _, v2 := range this.firstChargeList { if v.productId == v2.ProductId { str, ret := redis.String_Get(fmt.Sprintf("%d:%s", userId, v2.ProductId)) if !ret || str == "" { return false } } } } return true } /* // 充值记录 func (this *shopmgr) getRechargeList(userId, shopType int) []*rechargeInfo { return getRechargeList(userId, shopType) } // 币种列表 func (this *shopmgr) getExchangeRateList() []*exchangeRate { this.lock.RLock() defer this.lock.RUnlock() return this.exchangeRateList } // 获取币种信息,传空信息的话,默认选择一个币种 func (this *shopmgr) exchangeRateInfo(currency string) *exchangeRate { this.lock.RLock() defer this.lock.RUnlock() for _, v := range this.exchangeRateList { if currency == "" { return v } if v.Currency == currency { return v } } return nil } */ func (this *shopmgr) dump(param1, param2 string) { log.Release("-------------------------------") log.Release("shopmgr.dump %s", param1) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() shopType, err := strconv.Atoi(param1) if err != nil { for i := ShopType_Gold; i < ShopType_Max; i++ { shopList := this.getShopList(0, i) if len(shopList) == 0 { continue } log.Release(" Type[%d]:", i) for _, v := range shopList { this.dumpShopItem(v) } } } else { shopList := this.getShopList(0, shopType) for _, v := range shopList { this.dumpShopItem(v) } } } func (this *shopmgr) dumpShopItem(si *Shop_Item) { price := fmt.Sprintf("%v", si.Price) showPrice := fmt.Sprintf("%v", si.ShowPrice) /*if si.PayType == PayType_RMB { this.lock.RLock() for _, v := range this.exchangeRateList { if price == "" { price = fmt.Sprintf("%s[%.1f]", v.Currency, v.Rate*si.Price) showPrice = fmt.Sprintf("%s[%.1f]", v.Currency, v.Rate*si.ShowPrice) } else { price = fmt.Sprintf("%s,%s[%.1f]", price, v.Currency, v.Rate*si.Price) showPrice = fmt.Sprintf("%s,%s[%.1f]", showPrice, v.Currency, v.Rate*si.ShowPrice) } } this.lock.RUnlock() }*/ log.Release(" ProductId[%s],Name[%s],Price[%.1f],PayType[%d],ShopType[%d],IsHot[%d],Bonus[%d],Items:%v", si.ProductId, si.ProductName, si.Price, si.PayType, si.ShopType, si.IsHot, si.Bonus, si.Extra) log.Release(" Price:[%s],ShowPrice[%s]", price, showPrice) log.Release("") }