|
@@ -0,0 +1,276 @@
|
|
|
|
+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 // 订单中的产品类型
|
|
|
|
+ SaleDep 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. 判断库存
|
|
|
|
+ e.processEquityInfo(activeName, activeId, mold)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 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月
|
|
|
|
+ }
|
|
|
|
+ //其他不赠送
|
|
|
|
+ return
|
|
|
|
+ } else if e.OrderType == valueOrderTypeUpgrade {
|
|
|
|
+ // 升级
|
|
|
|
+ // 判断是否是年度会员 不是年度会员则不赠送 是则赠送1月
|
|
|
|
+ if e.isYearVip() {
|
|
|
|
+ ok = true
|
|
|
|
+ mold = valueMoldMonth
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 处理库存
|
|
|
|
+func (e *EquityActive) processEquityInfo(activeName string, activeId, mold int) {
|
|
|
|
+ count := 0
|
|
|
|
+ tx, err := util.Mysql.DB.Begin()
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("equityActive db Begin:", err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ countQuery := fmt.Sprintf("SELECT count(*) FROM %s where state= 0 and mold=? and active_id=? ;", TableEquityInfo)
|
|
|
|
+ rows, err := tx.Query(countQuery, mold, activeId)
|
|
|
|
+ if err != nil || rows == nil {
|
|
|
|
+ log.Println("获取剩余库存数量失败:", err, rows, e.OrderCode)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ defer rows.Close()
|
|
|
|
+ for rows.Next() {
|
|
|
|
+ err = rows.Scan(&count)
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("遍历剩余库存数量失败:", err, rows)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if count <= 0 {
|
|
|
|
+ log.Println("库存剩余为0:", countQuery, mold, activeId)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ 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=? limit 1 for update;", TableEquityInfo)
|
|
|
|
+ data, err := tx.Query(query, mold, activeId)
|
|
|
|
+ if err != nil || data == nil {
|
|
|
|
+ tx.Rollback()
|
|
|
|
+ log.Println("获取视频权益码信息失败:", err, data, e.OrderCode)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ eId, name, code, exEndTime := 0, "", "", ""
|
|
|
|
+ defer data.Close()
|
|
|
|
+ for data.Next() {
|
|
|
|
+ err = data.Scan(&eId, &name, &code, &exEndTime)
|
|
|
|
+ }
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("获取视频权益码失败:", err, data, e.OrderCode)
|
|
|
|
+ tx.Rollback()
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ threshold, b := config.Config.EquityActive.MailAlarm.Threshold[fmt.Sprintf("%v", mold)]
|
|
|
|
+ if count < 1 || eId <= 0 {
|
|
|
|
+ tx.Rollback()
|
|
|
|
+ // 没有库存
|
|
|
|
+ if b {
|
|
|
|
+ go e.sendAlarmMail(activeName, activeId, threshold.Name, mold, 0)
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if b && int(count)-1 <= threshold.Value {
|
|
|
|
+ // 发库存告警时这减去1是因为这一次消耗一个
|
|
|
|
+ go e.sendAlarmMail(activeName, activeId, threshold.Name, mold, int(count)-1)
|
|
|
|
+ }
|
|
|
|
+ update := fmt.Sprintf("update %s set order_code=?,state=?,update_time=? where id=? ", TableEquityInfo)
|
|
|
|
+ _, err = tx.Exec(update, e.OrderCode, valueStateGifted, date.NowFormat(date.Date_Full_Layout), eId)
|
|
|
|
+ if err != nil {
|
|
|
|
+ tx.Rollback()
|
|
|
|
+ log.Println("更新视频权益码失败", e.OrderCode, eId, err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ err = tx.Commit()
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("视频权益码commit失败", e.OrderCode, eId, err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ //6. 发送短信、站内信
|
|
|
|
+ go e.sendVipMsg(name, code, exEndTime)
|
|
|
|
+ return
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 根据订单号获取缓存里面的用户id等信息
|
|
|
|
+func (e *EquityActive) setUserID() {
|
|
|
|
+ orderKey := fmt.Sprintf("order_%s", e.OrderCode)
|
|
|
|
+ rs := redis.Get("other", orderKey)
|
|
|
|
+ info := common.ObjToMap(rs)
|
|
|
|
+ phone := ""
|
|
|
|
+ if info != nil && len(*info) > 0 {
|
|
|
|
+ log.Println("equityActive 未获取到redis保存的用户身份信息:", orderKey, info)
|
|
|
|
+ e.mgoId = common.ObjToString((*info)["mgoId"])
|
|
|
|
+ e.positionId = fmt.Sprintf("%v", common.IntAll((*info)["positionId"]))
|
|
|
|
+ phone = common.ObjToString((*info)["phone"])
|
|
|
|
+ }
|
|
|
|
+ if phone != "" {
|
|
|
|
+ e.Phone = phone
|
|
|
|
+ }
|
|
|
|
+ // 如果没有redis取到说明是代用户下单的订单
|
|
|
|
+ // 代用户下单的现在只有个人版的 所以可以直接从订单里面取用户mgoId
|
|
|
|
+ // 但是需要再判断业绩归属部门
|
|
|
|
+ if e.mgoId == "" && bson.IsObjectIdHex(e.UserId) && e.SaleDep != "" {
|
|
|
|
+ if _, ok := config.Config.EquityActive.SaleDep[e.SaleDep]; ok {
|
|
|
|
+ e.mgoId = e.UserId
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 发送消息
|
|
|
|
+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)
|
|
|
|
+ args4 = smsconfig.Args[1]
|
|
|
|
+ } 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, e.ProductType, eName, code),
|
|
|
|
+ MsgType: siteMsg.MsgType,
|
|
|
|
+ SendMode: 2,
|
|
|
|
+ }
|
|
|
|
+ util.EquityActiveSend.SendStationMessages(p)
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 库存告警
|
|
|
|
+func (e *EquityActive) sendAlarmMail(activeName string, activeId int, name string, mold, count int) {
|
|
|
|
+ ma := config.Config.EquityActive.MailAlarm
|
|
|
|
+ if len(ma.To) == 0 {
|
|
|
|
+ log.Println("未配置视频会员权益码活动库存告警邮箱")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ to := strings.Join(ma.To, ",")
|
|
|
|
+ content := fmt.Sprintf("活动:%s(活动id:%d),%s权益(mold:%d)当前库存:%d", activeName, activeId, name, mold, 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
|
|
|
|
+}
|