You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
9.6 KiB
349 lines
9.6 KiB
package service |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
"time" |
|
|
|
"go-common/app/job/main/vip/model" |
|
"go-common/library/log" |
|
|
|
"github.com/pkg/errors" |
|
) |
|
|
|
//ScanSalaryVideoCoupon scan all vip user to salary video coupon. |
|
func (s *Service) ScanSalaryVideoCoupon(c context.Context) (err error) { |
|
var ( |
|
userInfos []*model.VipInfoDB |
|
size = 100 |
|
endID int |
|
now = time.Now() |
|
dv = now.Format("2006_01") |
|
y = now.Year() |
|
m = now.Month() |
|
salaryDate = time.Date(y, m, s.c.Property.SalaryDay, 0, 0, 0, 0, time.Local) |
|
) |
|
for { |
|
if endID, err = s.dao.SelUserInfoMaxID(context.TODO()); err != nil { |
|
log.Error("s.dao.SelMaxID error(%v)", err) |
|
time.Sleep(time.Minute * 2) |
|
continue |
|
} |
|
break |
|
} |
|
page := endID / size |
|
if endID%size != 0 { |
|
page++ |
|
} |
|
for i := 0; i < page; { |
|
log.Info("salary page(%d) total(%d) ....................................", i, page) |
|
startID := i * size |
|
eID := (i + 1) * size |
|
if userInfos, err = s.dao.SelEffectiveScopeVipList(context.TODO(), startID, eID); err != nil { |
|
log.Error("s.dao.SelEffectiveScopeVipList error(%v)", err) |
|
time.Sleep(time.Second * 5) |
|
continue |
|
} |
|
i++ |
|
for _, v := range userInfos { |
|
time.Sleep(time.Duration(s.c.Property.SalaryVideoCouponnIterval)) |
|
var ( |
|
vipType = model.NotVip |
|
) |
|
if v.Status != model.VipStatusNotOverTime && v.Status != model.VipStatusFrozen { |
|
continue |
|
} |
|
if salaryDate.Before(v.OverdueTime.Time()) { |
|
vipType = model.Vip |
|
if salaryDate.Before(v.AnnualVipOverdueTime.Time()) { |
|
vipType = model.AnnualVip |
|
} |
|
} |
|
if vipType == model.NotVip { |
|
continue |
|
} |
|
day := v.OverdueTime.Time().Sub(v.RecentTime.Time()).Hours() / model.DayOfHour |
|
if day < model.VipDaysMonth { |
|
continue |
|
} |
|
if err = s.salaryCoupon(c, v.Mid, model.TimingSalaryType, int8(vipType), dv, model.CouponSalaryTiming); err != nil { |
|
err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", v.Mid, v) |
|
log.Error("%+v", err) |
|
continue |
|
} |
|
log.Info("salary suc mid(%d) ....................................", v.Mid) |
|
} |
|
} |
|
return |
|
} |
|
|
|
// salaryCoupon salary coupon. |
|
func (s *Service) salaryCoupon(c context.Context, mid int64, salaryType int8, vipType int8, dv string, atonce int8) (err error) { |
|
var ( |
|
logs []*model.VideoCouponSalaryLog |
|
hs = map[int8]int64{} // key:coupontype value:salarycount |
|
ms map[string]int64 // key:viptype value:salarycount |
|
) |
|
if logs, err = s.dao.SalaryVideoCouponList(c, mid, dv); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
for _, v := range logs { |
|
hs[v.CouponType] = hs[v.CouponType] + v.CouponCount |
|
} |
|
for _, v := range s.c.Property.SalaryCouponTypes { |
|
ms = s.c.Property.SalaryCouponMaps[fmt.Sprintf("%d", v)] |
|
if len(ms) != 0 { |
|
if salaryType == model.VipSupplyType { |
|
if hs[v] == 0 { |
|
hs[v] = ms[fmt.Sprintf("%d", model.AnnualVip)] - ms[fmt.Sprintf("%d", model.Vip)] |
|
} else { |
|
hs[v] = ms[fmt.Sprintf("%d", model.AnnualVip)] - hs[v] |
|
} |
|
} else { |
|
hs[v] = ms[fmt.Sprintf("%d", vipType)] - hs[v] |
|
} |
|
} |
|
} |
|
for k, count := range hs { |
|
var ( |
|
token string |
|
tokenfmt string |
|
) |
|
if count <= 0 { |
|
continue |
|
} |
|
tokenfmt = s.c.Property.SalaryCouponBatchNoMaps[fmt.Sprintf("%d", k)] |
|
if len(tokenfmt) == 0 { |
|
continue |
|
} |
|
token = fmt.Sprintf(tokenfmt, atonce, dv) |
|
if err = s.dao.SalaryCoupon(c, mid, k, count, token); err != nil { |
|
err = errors.Wrapf(err, "s.dao.SalaryCoupon(%d)", mid) |
|
return |
|
} |
|
l := &model.VideoCouponSalaryLog{ |
|
Mid: mid, |
|
CouponCount: count, |
|
State: model.HadSalaryState, |
|
Type: salaryType, |
|
CouponType: k, |
|
} |
|
if err = s.dao.AddSalaryLog(c, l, dv); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if s.c.Property.MsgOpen { |
|
var ( |
|
title string |
|
content string |
|
) |
|
title = s.c.Property.SalaryCouponMsgTitleMaps[fmt.Sprintf("%d", k)] |
|
if len(title) == 0 { |
|
continue |
|
} |
|
if salaryType == model.VipSupplyType { |
|
content = s.c.Property.SalaryCouponMsgSupplyContentMaps[fmt.Sprintf("%d", k)] |
|
if len(content) == 0 { |
|
continue |
|
} |
|
content = fmt.Sprintf(content, count) |
|
} else { |
|
content = s.c.Property.SalaryCouponMsgContentMaps[fmt.Sprintf("%d", k)] |
|
if len(content) == 0 { |
|
continue |
|
} |
|
} |
|
s.sendmessage(func() { |
|
s.dao.SendMultipMsg(context.TODO(), fmt.Sprintf("%d", mid), content, |
|
title, model.MsgCouponSalaryMc, model.MsgSystemNotify) |
|
}) |
|
} |
|
} |
|
return |
|
} |
|
|
|
// SalaryVideoCouponAtOnce salary video coupon at once. |
|
func (s *Service) SalaryVideoCouponAtOnce(c context.Context, nvip *model.VipUserInfoMsg, ovip *model.VipUserInfoMsg, act string) (res int, err error) { |
|
if act == _insertAction { |
|
if err = s.salaryInsertAct(c, nvip); err != nil { |
|
err = errors.Wrapf(err, "salaryInsertAct (%v)", nvip) |
|
return |
|
} |
|
} else if act == _updateAction { |
|
if err = s.salaryUpdateAct(c, nvip, ovip); err != nil { |
|
err = errors.Wrapf(err, "salaryInsertAct (%v)", nvip) |
|
return |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) salaryInsertAct(c context.Context, nvip *model.VipUserInfoMsg) (err error) { |
|
var ( |
|
now = time.Now() |
|
otime time.Time |
|
aotime time.Time |
|
vipType = model.NotVip |
|
zeroTime = now.AddDate(-10, 0, 0) |
|
salaryType int8 |
|
dv = now.Format("2006_01") |
|
) |
|
otime, err = time.ParseInLocation(model.TimeFormatSec, nvip.OverdueTime, time.Local) |
|
if err != nil { |
|
log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", nvip.OverdueTime)) |
|
otime = zeroTime |
|
err = nil |
|
} |
|
aotime, err = time.ParseInLocation(model.TimeFormatSec, nvip.AnnualVipOverdueTime, time.Local) |
|
if err != nil { |
|
aotime = zeroTime |
|
err = nil |
|
} |
|
if nvip.Status != model.VipStatusNotOverTime && nvip.Status != model.VipStatusFrozen { |
|
return |
|
} |
|
days := otime.Sub(now).Hours() / model.DayOfHour |
|
if days < model.VipDaysMonth { |
|
log.Info("cur user not enough send coupon (%+v)", nvip) |
|
return |
|
} |
|
if now.Before(otime) { |
|
vipType = model.Vip |
|
if now.Before(aotime) { |
|
vipType = model.AnnualVip |
|
} |
|
} |
|
switch vipType { |
|
case model.Vip: |
|
salaryType = model.NormalVipSalaryType |
|
case model.AnnualVip: |
|
salaryType = model.AnnualVipSalaryType |
|
default: |
|
return |
|
} |
|
if err = s.salaryCoupon(c, int64(nvip.Mid), salaryType, int8(vipType), dv, model.CouponSalaryAtonce); err != nil { |
|
err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", nvip.Mid, nvip) |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) salaryUpdateAct(c context.Context, nvip *model.VipUserInfoMsg, ovip *model.VipUserInfoMsg) (err error) { |
|
var ( |
|
ovType int |
|
nvType int |
|
expire bool |
|
now = time.Now() |
|
zeroTime = now.AddDate(-10, 0, 0) |
|
ntime time.Time |
|
oatime time.Time |
|
natime time.Time |
|
salaryType int8 |
|
dv = now.Format("2006_01") |
|
) |
|
ntime, err = time.ParseInLocation(model.TimeFormatSec, nvip.OverdueTime, time.Local) |
|
if err != nil { |
|
log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", nvip.OverdueTime)) |
|
ntime = zeroTime |
|
err = nil |
|
} |
|
natime, err = time.ParseInLocation(model.TimeFormatSec, nvip.AnnualVipOverdueTime, time.Local) |
|
if err != nil { |
|
natime = zeroTime |
|
err = nil |
|
} |
|
// check OverdueTime time. |
|
if ntime.Before(now) { |
|
return |
|
} |
|
nvType = model.Vip |
|
// check AnnualVipOverdueTime time. |
|
if now.Before(natime) { |
|
nvType = model.AnnualVip |
|
} |
|
// check old vip info expire. |
|
expire, _ = s.judgeVipExpire(c, ovip) |
|
if expire { |
|
//check open days is enough 31 |
|
days := ntime.Sub(now).Hours() / model.DayOfHour |
|
if days < model.VipDaysMonth { |
|
log.Info("cur user not enough send coupon (%+v)", nvip) |
|
return |
|
} |
|
if nvType == model.Vip { |
|
// expire vip -> vip |
|
salaryType = model.NormalVipSalaryType |
|
} else if nvType == model.AnnualVip { |
|
// expire vip -> annual vip |
|
salaryType = model.AnnualVipSalaryType |
|
} |
|
} else { |
|
if ovip.Type == model.Vip { |
|
ovType = model.Vip |
|
} |
|
|
|
oatime, err = time.ParseInLocation(model.TimeFormatSec, ovip.AnnualVipOverdueTime, time.Local) |
|
if err != nil { |
|
oatime = zeroTime |
|
err = nil |
|
} |
|
if ovip.Type == model.AnnualVip && oatime.After(now) { |
|
ovType = model.AnnualVip |
|
} |
|
if ovType == model.Vip && nvType == model.AnnualVip { |
|
// normal vip -> annual vip |
|
salaryType = model.VipSupplyType |
|
} |
|
// short vip -> normal vip |
|
recentTime := parseTime(ovip.RecentTime) |
|
otime := parseTime(ovip.OverdueTime) |
|
days := otime.Sub(recentTime).Hours() / model.DayOfHour |
|
if days < model.VipDaysMonth { |
|
//check open days is enough 31 |
|
days := ntime.Sub(now).Hours() / model.DayOfHour |
|
if days < model.VipDaysMonth { |
|
log.Info("cur user not enough send coupon (%+v)", nvip) |
|
return |
|
} |
|
if nvType == model.Vip { |
|
// expire vip -> vip |
|
salaryType = model.NormalVipSalaryType |
|
} else if nvType == model.AnnualVip { |
|
// expire vip -> annual vip |
|
salaryType = model.AnnualVipSalaryType |
|
} |
|
} |
|
|
|
} |
|
switch salaryType { |
|
case model.NormalVipSalaryType, model.AnnualVipSalaryType, model.VipSupplyType: |
|
if err = s.salaryCoupon(c, int64(nvip.Mid), salaryType, int8(nvType), dv, model.CouponSalaryAtonce); err != nil { |
|
err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", int64(nvip.Mid), nvip) |
|
} |
|
} |
|
return |
|
} |
|
|
|
// judgeVipExpire judge vip is expire. |
|
func (s *Service) judgeVipExpire(c context.Context, v *model.VipUserInfoMsg) (expire bool, err error) { |
|
var ( |
|
now = time.Now() |
|
overdueTime time.Time |
|
zeroTime = now.AddDate(-10, 0, 0) |
|
) |
|
if v.Status != model.VipStatusNotOverTime && v.Status != model.VipStatusFrozen { |
|
expire = true |
|
return |
|
} |
|
overdueTime, err = time.ParseInLocation(model.TimeFormatSec, v.OverdueTime, time.Local) |
|
if err != nil { |
|
log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", v.OverdueTime)) |
|
overdueTime = zeroTime |
|
err = nil |
|
} |
|
if overdueTime.Before(now) { |
|
expire = true |
|
return |
|
} |
|
return |
|
}
|
|
|