|
@@ -0,0 +1,242 @@
|
|
|
+package entity
|
|
|
+
|
|
|
+import (
|
|
|
+ "app.yhyue.com/moapp/jybase/common"
|
|
|
+ "app.yhyue.com/moapp/jybase/date"
|
|
|
+ "app.yhyue.com/moapp/jybase/redis"
|
|
|
+ "app.yhyue.com/moapp/jybase/sms"
|
|
|
+ "fmt"
|
|
|
+ "gopkg.in/mgo.v2/bson"
|
|
|
+ "jy/src/jfw/modules/subscribepay/src/config"
|
|
|
+ "jy/src/jfw/modules/subscribepay/src/util"
|
|
|
+ "log"
|
|
|
+ "regexp"
|
|
|
+ "strings"
|
|
|
+ "sync"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ TableEquityInfo = "jyactivities.equity_info" // 营销权益信息表
|
|
|
+ TableEquityActive = "jyactivities.equity_active" // 营销权益活动表
|
|
|
+ TableOrder = "jianyu.dataexport_order" // 订单表
|
|
|
+ TablebasePosition = "base_service.base_position" // 用户职位表
|
|
|
+ valueStateGifted = 1 // 已赠送状态值
|
|
|
+ valueMoldMonth = 0 // 月度
|
|
|
+ valueMoldYear = 1 // 年度
|
|
|
+ valueOrderTypeCreate = 1 // 超级订阅订单类型: 购买
|
|
|
+ valueOrderTypeRenew = 2 // 续费
|
|
|
+ valueOrderTypeUpgrade = 3 // 升级
|
|
|
+ valueCycleUnitYear = 1 // 周期单位为年
|
|
|
+ valueAreaCountAll = -1 // 全国
|
|
|
+
|
|
|
+)
|
|
|
+
|
|
|
+var equityStockLock = sync.Mutex{} // 赠送视频权益码库存锁
|
|
|
+// EquityActive 赠送视频会员活动
|
|
|
+type EquityActive struct {
|
|
|
+ UserId string // id 这边取到的id可能是职位id也可能是mongo库id
|
|
|
+ mgoId string // mongo库id
|
|
|
+ positionId string // 职位id
|
|
|
+ Phone string // 手机号 用于发短信
|
|
|
+ OrderCode string // 订单号
|
|
|
+ OrderType int // 1购买 2升级 3续费
|
|
|
+ CycleUnit int // 单位 1-年
|
|
|
+ CycleCount int // 数量
|
|
|
+ AreaCount int // -1 是全国
|
|
|
+ ProductType string // 消息中的产品类型
|
|
|
+ OrderProductType string // 订单中的产品类型
|
|
|
+}
|
|
|
+
|
|
|
+// GiftVip 赠送腾讯视频会员
|
|
|
+func (e *EquityActive) GiftVip() {
|
|
|
+ //1. 判断活动是否开启
|
|
|
+ open, activeId, activeName := e.activityStart()
|
|
|
+ if !open || activeId <= 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 获取 缓存中的用户信息
|
|
|
+ e.setUserID()
|
|
|
+ if e.mgoId == "" {
|
|
|
+ log.Println("equityActive 未获取到有效的mgoId", e.OrderCode)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //2. 判断是否符合赠送条件
|
|
|
+ ok, mold := e.matchOrder()
|
|
|
+ if !ok {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ equityStockLock.Lock()
|
|
|
+ defer func() {
|
|
|
+ equityStockLock.Unlock()
|
|
|
+ }()
|
|
|
+ //3. 判断库存
|
|
|
+ eInfo := e.findVipStock(activeId, mold)
|
|
|
+ if eInfo == nil || len(*eInfo) == 0 {
|
|
|
+ // 没有库存
|
|
|
+ go e.sendAlarmMail(activeName, activeId, mold, 0)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if len(*eInfo) <= config.Config.EquityActive.MailAlarm.Threshold {
|
|
|
+ // 发库存告警时这减去1是因为这一次马上会消耗一个
|
|
|
+ go e.sendAlarmMail(activeName, activeId, mold, len(*eInfo)-1)
|
|
|
+ }
|
|
|
+ eId := common.IntAll((*eInfo)[0]["id"])
|
|
|
+ //4. 更新库存
|
|
|
+ if !e.updateVipStock(eId) {
|
|
|
+ log.Println("equityActive 更新库存信息失败:", eId, e.OrderCode)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //6. 发送短信、站内信
|
|
|
+ eName := common.ObjToString((*eInfo)[0]["name"])
|
|
|
+ code := common.ObjToString((*eInfo)[0]["code"])
|
|
|
+ exEndTime := common.ObjToString((*eInfo)[0]["ex_end_time"])
|
|
|
+ go e.sendVipMsg(eName, code, exEndTime)
|
|
|
+}
|
|
|
+
|
|
|
+// txActivityStart 判断活动是否开启 开启则返回活动id
|
|
|
+func (e *EquityActive) activityStart() (open bool, id int, name string) {
|
|
|
+ now := date.NowFormat(date.Date_Full_Layout)
|
|
|
+ query := fmt.Sprintf("SELECT id,name FROM %s where state=0 and start_time<=? and end_time>=?;", TableEquityActive)
|
|
|
+ rs := util.Mysql.SelectBySql(query, now, now)
|
|
|
+ if rs != nil && len(*rs) > 0 {
|
|
|
+ open = true
|
|
|
+ id = common.IntAll((*rs)[0]["id"])
|
|
|
+ name = common.ObjToString((*rs)[0]["name"])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// 判断订单是否符合条件
|
|
|
+func (e *EquityActive) matchOrder() (ok bool, mold int) {
|
|
|
+ //(购买||续费)
|
|
|
+ if (e.OrderType == valueOrderTypeCreate || e.OrderType == valueOrderTypeRenew) && e.CycleCount > 0 {
|
|
|
+ // 判断购买是否为年度订单
|
|
|
+ if e.CycleUnit != valueCycleUnitYear {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 为年度订单则判断是否为全国
|
|
|
+ if e.AreaCount == valueAreaCountAll {
|
|
|
+ ok = true
|
|
|
+ mold = valueMoldYear //全国赠送1年
|
|
|
+ } else {
|
|
|
+ ok = true
|
|
|
+ mold = valueMoldMonth //非全国赠送1月
|
|
|
+ }
|
|
|
+ //其他不赠送 // 升级
|
|
|
+ // 判断是否是年度会员 不是年度会员则不赠送 是则赠送1月
|
|
|
+ return
|
|
|
+ } else if e.OrderType == valueOrderTypeUpgrade {
|
|
|
+ // 升级
|
|
|
+ // 判断是否是年度会员 不是年度会员则不赠送 是则赠送1月
|
|
|
+ if e.isYearVip() {
|
|
|
+ ok = true
|
|
|
+ mold = valueMoldMonth
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// 查看兑换权益码信息
|
|
|
+func (e *EquityActive) findVipStock(activeId, mold int) (data *[]map[string]interface{}) {
|
|
|
+ query := fmt.Sprintf("SELECT id,name,code,date_format(ex_end_time,'%%Y-%%m-%%d') as ex_end_time FROM %s where state= 0 and mold=? and active_id=? ;", TableEquityInfo)
|
|
|
+ data = util.Mysql.SelectBySql(query, mold, activeId)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// 根据订单号获取缓存里面的用户id等信息
|
|
|
+func (e *EquityActive) setUserID() (mgoId string, positionId string) {
|
|
|
+ orderKey := fmt.Sprintf("order_%s", e.OrderCode)
|
|
|
+ rs := redis.Get("other", orderKey)
|
|
|
+ info := common.ObjToMap(rs)
|
|
|
+ if info == nil || len(*info) == 0 {
|
|
|
+ log.Println("equityActive 未获取到redis保存的用户身份信息:", orderKey, info)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ mgoId = common.ObjToString((*info)["mgoId"])
|
|
|
+ positionId = fmt.Sprintf("%v", common.IntAll((*info)["positionId"]))
|
|
|
+ phone := common.ObjToString((*info)["phone"])
|
|
|
+ if phone != "" {
|
|
|
+ e.Phone = phone
|
|
|
+ }
|
|
|
+ e.mgoId = mgoId
|
|
|
+ e.positionId = positionId
|
|
|
+ if mgoId == "" && bson.IsObjectIdHex(e.UserId) {
|
|
|
+ // 如果没有redis取到说明是代用户下单的订单
|
|
|
+ // 代用户下单的现在只有个人版的 所以可以直接从订单里面取用户mgoId
|
|
|
+ if bson.IsObjectIdHex(e.UserId) {
|
|
|
+ mgoId = e.UserId
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// 更新库存
|
|
|
+func (e *EquityActive) updateVipStock(eInfoId int) bool {
|
|
|
+ update := fmt.Sprintf("update %s set order_code=?,state=?,update_time=? where id=? ", TableEquityInfo)
|
|
|
+ return util.Mysql.UpdateOrDeleteBySql(update, e.OrderCode, valueStateGifted, date.NowFormat(date.Date_Full_Layout), eInfoId) > 0
|
|
|
+}
|
|
|
+
|
|
|
+// 发送消息
|
|
|
+func (e *EquityActive) sendVipMsg(eName, code, ex_end_time string) {
|
|
|
+ // 发送短信
|
|
|
+ // 04 短信模板:用户{1}您好,购买{2}产品赠送您{3},请前往{4}进行兑换解锁福利。
|
|
|
+ // 手机号处理
|
|
|
+ if e.Phone != "" {
|
|
|
+ phone := e.Phone
|
|
|
+ var PhoneReg = regexp.MustCompile(`^(100\d{8}|1[3-9]\d{9})$`)
|
|
|
+ if PhoneReg.MatchString(e.Phone) {
|
|
|
+ phone = string(phone[0:3]) + "****" + string(phone[(len(phone)-4):])
|
|
|
+ }
|
|
|
+ smsconfig := config.Config.EquityActive.Sms
|
|
|
+ args3, args4 := "", ""
|
|
|
+ if len(smsconfig.Args) == 2 {
|
|
|
+ args3 = fmt.Sprintf(smsconfig.Args[0], eName, code, ex_end_time)
|
|
|
+ } else {
|
|
|
+ log.Println("equityActive 视频会员活动短信模板内容参数配置异常,请检查配置文件。")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ params := []string{phone, e.ProductType, args3, args4}
|
|
|
+ sms.SendSms(config.Config.SmsServiceRpc, smsconfig.Tid, e.Phone, params...)
|
|
|
+ } else {
|
|
|
+ log.Println("equityActive 未获取到用户手机号,不再发送短信:", e.OrderCode, e.UserId, e.Phone)
|
|
|
+ }
|
|
|
+ siteMsg := config.Config.EquityActive.SiteMsg
|
|
|
+ // 发送站内信
|
|
|
+ p := util.MessageParam{
|
|
|
+ UserIds: e.mgoId,
|
|
|
+ PositionIds: e.positionId,
|
|
|
+ Title: fmt.Sprintf(siteMsg.Title, eName),
|
|
|
+ Content: fmt.Sprintf(siteMsg.Content, e.ProductType, eName, code, ex_end_time),
|
|
|
+ MsgType: siteMsg.MsgType,
|
|
|
+ SendMode: 2,
|
|
|
+ }
|
|
|
+ util.EquityActiveSend.SendStationMessages(p)
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// 库存告警
|
|
|
+func (e *EquityActive) sendAlarmMail(activeName string, activeId, mold, count int) {
|
|
|
+ ma := config.Config.EquityActive.MailAlarm
|
|
|
+ if len(ma.To) == 0 {
|
|
|
+ log.Println("未配置视频会员权益码活动库存告警邮箱")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ to := strings.Join(ma.To, ",")
|
|
|
+ m := ""
|
|
|
+ if mold == valueMoldYear {
|
|
|
+ m = "年度"
|
|
|
+ } else {
|
|
|
+ m = "月度"
|
|
|
+ }
|
|
|
+ content := fmt.Sprintf("活动:%s(活动id:%d),%s权益当前库存:%d", activeName, activeId, m, count)
|
|
|
+ util.SendRetryMailMany(ma.ReTry, to, ma.Title, content, "", "", config.GmailAuth)
|
|
|
+}
|
|
|
+
|
|
|
+// 判断是否年度会员
|
|
|
+func (e *EquityActive) isYearVip() bool {
|
|
|
+ query := fmt.Sprintf("select count(*) from %s where user_id=? and order_status=1 and product_type =? and (timestampdiff(day,vip_starttime,vip_endtime)>=365) order by create_time desc limit 1", TableOrder)
|
|
|
+ count := util.Mysql.CountBySql(query, e.UserId, e.OrderProductType)
|
|
|
+ log.Println("isYearVip 判断是否为年度订单:", query, e.UserId, count)
|
|
|
+ return count > 0
|
|
|
+}
|