salary.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "go-common/app/job/main/vip/model"
  7. "go-common/library/log"
  8. "github.com/pkg/errors"
  9. )
  10. //ScanSalaryVideoCoupon scan all vip user to salary video coupon.
  11. func (s *Service) ScanSalaryVideoCoupon(c context.Context) (err error) {
  12. var (
  13. userInfos []*model.VipInfoDB
  14. size = 100
  15. endID int
  16. now = time.Now()
  17. dv = now.Format("2006_01")
  18. y = now.Year()
  19. m = now.Month()
  20. salaryDate = time.Date(y, m, s.c.Property.SalaryDay, 0, 0, 0, 0, time.Local)
  21. )
  22. for {
  23. if endID, err = s.dao.SelUserInfoMaxID(context.TODO()); err != nil {
  24. log.Error("s.dao.SelMaxID error(%v)", err)
  25. time.Sleep(time.Minute * 2)
  26. continue
  27. }
  28. break
  29. }
  30. page := endID / size
  31. if endID%size != 0 {
  32. page++
  33. }
  34. for i := 0; i < page; {
  35. log.Info("salary page(%d) total(%d) ....................................", i, page)
  36. startID := i * size
  37. eID := (i + 1) * size
  38. if userInfos, err = s.dao.SelEffectiveScopeVipList(context.TODO(), startID, eID); err != nil {
  39. log.Error("s.dao.SelEffectiveScopeVipList error(%v)", err)
  40. time.Sleep(time.Second * 5)
  41. continue
  42. }
  43. i++
  44. for _, v := range userInfos {
  45. time.Sleep(time.Duration(s.c.Property.SalaryVideoCouponnIterval))
  46. var (
  47. vipType = model.NotVip
  48. )
  49. if v.Status != model.VipStatusNotOverTime && v.Status != model.VipStatusFrozen {
  50. continue
  51. }
  52. if salaryDate.Before(v.OverdueTime.Time()) {
  53. vipType = model.Vip
  54. if salaryDate.Before(v.AnnualVipOverdueTime.Time()) {
  55. vipType = model.AnnualVip
  56. }
  57. }
  58. if vipType == model.NotVip {
  59. continue
  60. }
  61. day := v.OverdueTime.Time().Sub(v.RecentTime.Time()).Hours() / model.DayOfHour
  62. if day < model.VipDaysMonth {
  63. continue
  64. }
  65. if err = s.salaryCoupon(c, v.Mid, model.TimingSalaryType, int8(vipType), dv, model.CouponSalaryTiming); err != nil {
  66. err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", v.Mid, v)
  67. log.Error("%+v", err)
  68. continue
  69. }
  70. log.Info("salary suc mid(%d) ....................................", v.Mid)
  71. }
  72. }
  73. return
  74. }
  75. // salaryCoupon salary coupon.
  76. func (s *Service) salaryCoupon(c context.Context, mid int64, salaryType int8, vipType int8, dv string, atonce int8) (err error) {
  77. var (
  78. logs []*model.VideoCouponSalaryLog
  79. hs = map[int8]int64{} // key:coupontype value:salarycount
  80. ms map[string]int64 // key:viptype value:salarycount
  81. )
  82. if logs, err = s.dao.SalaryVideoCouponList(c, mid, dv); err != nil {
  83. err = errors.WithStack(err)
  84. return
  85. }
  86. for _, v := range logs {
  87. hs[v.CouponType] = hs[v.CouponType] + v.CouponCount
  88. }
  89. for _, v := range s.c.Property.SalaryCouponTypes {
  90. ms = s.c.Property.SalaryCouponMaps[fmt.Sprintf("%d", v)]
  91. if len(ms) != 0 {
  92. if salaryType == model.VipSupplyType {
  93. if hs[v] == 0 {
  94. hs[v] = ms[fmt.Sprintf("%d", model.AnnualVip)] - ms[fmt.Sprintf("%d", model.Vip)]
  95. } else {
  96. hs[v] = ms[fmt.Sprintf("%d", model.AnnualVip)] - hs[v]
  97. }
  98. } else {
  99. hs[v] = ms[fmt.Sprintf("%d", vipType)] - hs[v]
  100. }
  101. }
  102. }
  103. for k, count := range hs {
  104. var (
  105. token string
  106. tokenfmt string
  107. )
  108. if count <= 0 {
  109. continue
  110. }
  111. tokenfmt = s.c.Property.SalaryCouponBatchNoMaps[fmt.Sprintf("%d", k)]
  112. if len(tokenfmt) == 0 {
  113. continue
  114. }
  115. token = fmt.Sprintf(tokenfmt, atonce, dv)
  116. if err = s.dao.SalaryCoupon(c, mid, k, count, token); err != nil {
  117. err = errors.Wrapf(err, "s.dao.SalaryCoupon(%d)", mid)
  118. return
  119. }
  120. l := &model.VideoCouponSalaryLog{
  121. Mid: mid,
  122. CouponCount: count,
  123. State: model.HadSalaryState,
  124. Type: salaryType,
  125. CouponType: k,
  126. }
  127. if err = s.dao.AddSalaryLog(c, l, dv); err != nil {
  128. err = errors.WithStack(err)
  129. return
  130. }
  131. if s.c.Property.MsgOpen {
  132. var (
  133. title string
  134. content string
  135. )
  136. title = s.c.Property.SalaryCouponMsgTitleMaps[fmt.Sprintf("%d", k)]
  137. if len(title) == 0 {
  138. continue
  139. }
  140. if salaryType == model.VipSupplyType {
  141. content = s.c.Property.SalaryCouponMsgSupplyContentMaps[fmt.Sprintf("%d", k)]
  142. if len(content) == 0 {
  143. continue
  144. }
  145. content = fmt.Sprintf(content, count)
  146. } else {
  147. content = s.c.Property.SalaryCouponMsgContentMaps[fmt.Sprintf("%d", k)]
  148. if len(content) == 0 {
  149. continue
  150. }
  151. }
  152. s.sendmessage(func() {
  153. s.dao.SendMultipMsg(context.TODO(), fmt.Sprintf("%d", mid), content,
  154. title, model.MsgCouponSalaryMc, model.MsgSystemNotify)
  155. })
  156. }
  157. }
  158. return
  159. }
  160. // SalaryVideoCouponAtOnce salary video coupon at once.
  161. func (s *Service) SalaryVideoCouponAtOnce(c context.Context, nvip *model.VipUserInfoMsg, ovip *model.VipUserInfoMsg, act string) (res int, err error) {
  162. if act == _insertAction {
  163. if err = s.salaryInsertAct(c, nvip); err != nil {
  164. err = errors.Wrapf(err, "salaryInsertAct (%v)", nvip)
  165. return
  166. }
  167. } else if act == _updateAction {
  168. if err = s.salaryUpdateAct(c, nvip, ovip); err != nil {
  169. err = errors.Wrapf(err, "salaryInsertAct (%v)", nvip)
  170. return
  171. }
  172. }
  173. return
  174. }
  175. func (s *Service) salaryInsertAct(c context.Context, nvip *model.VipUserInfoMsg) (err error) {
  176. var (
  177. now = time.Now()
  178. otime time.Time
  179. aotime time.Time
  180. vipType = model.NotVip
  181. zeroTime = now.AddDate(-10, 0, 0)
  182. salaryType int8
  183. dv = now.Format("2006_01")
  184. )
  185. otime, err = time.ParseInLocation(model.TimeFormatSec, nvip.OverdueTime, time.Local)
  186. if err != nil {
  187. log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", nvip.OverdueTime))
  188. otime = zeroTime
  189. err = nil
  190. }
  191. aotime, err = time.ParseInLocation(model.TimeFormatSec, nvip.AnnualVipOverdueTime, time.Local)
  192. if err != nil {
  193. aotime = zeroTime
  194. err = nil
  195. }
  196. if nvip.Status != model.VipStatusNotOverTime && nvip.Status != model.VipStatusFrozen {
  197. return
  198. }
  199. days := otime.Sub(now).Hours() / model.DayOfHour
  200. if days < model.VipDaysMonth {
  201. log.Info("cur user not enough send coupon (%+v)", nvip)
  202. return
  203. }
  204. if now.Before(otime) {
  205. vipType = model.Vip
  206. if now.Before(aotime) {
  207. vipType = model.AnnualVip
  208. }
  209. }
  210. switch vipType {
  211. case model.Vip:
  212. salaryType = model.NormalVipSalaryType
  213. case model.AnnualVip:
  214. salaryType = model.AnnualVipSalaryType
  215. default:
  216. return
  217. }
  218. if err = s.salaryCoupon(c, int64(nvip.Mid), salaryType, int8(vipType), dv, model.CouponSalaryAtonce); err != nil {
  219. err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", nvip.Mid, nvip)
  220. }
  221. return
  222. }
  223. func (s *Service) salaryUpdateAct(c context.Context, nvip *model.VipUserInfoMsg, ovip *model.VipUserInfoMsg) (err error) {
  224. var (
  225. ovType int
  226. nvType int
  227. expire bool
  228. now = time.Now()
  229. zeroTime = now.AddDate(-10, 0, 0)
  230. ntime time.Time
  231. oatime time.Time
  232. natime time.Time
  233. salaryType int8
  234. dv = now.Format("2006_01")
  235. )
  236. ntime, err = time.ParseInLocation(model.TimeFormatSec, nvip.OverdueTime, time.Local)
  237. if err != nil {
  238. log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", nvip.OverdueTime))
  239. ntime = zeroTime
  240. err = nil
  241. }
  242. natime, err = time.ParseInLocation(model.TimeFormatSec, nvip.AnnualVipOverdueTime, time.Local)
  243. if err != nil {
  244. natime = zeroTime
  245. err = nil
  246. }
  247. // check OverdueTime time.
  248. if ntime.Before(now) {
  249. return
  250. }
  251. nvType = model.Vip
  252. // check AnnualVipOverdueTime time.
  253. if now.Before(natime) {
  254. nvType = model.AnnualVip
  255. }
  256. // check old vip info expire.
  257. expire, _ = s.judgeVipExpire(c, ovip)
  258. if expire {
  259. //check open days is enough 31
  260. days := ntime.Sub(now).Hours() / model.DayOfHour
  261. if days < model.VipDaysMonth {
  262. log.Info("cur user not enough send coupon (%+v)", nvip)
  263. return
  264. }
  265. if nvType == model.Vip {
  266. // expire vip -> vip
  267. salaryType = model.NormalVipSalaryType
  268. } else if nvType == model.AnnualVip {
  269. // expire vip -> annual vip
  270. salaryType = model.AnnualVipSalaryType
  271. }
  272. } else {
  273. if ovip.Type == model.Vip {
  274. ovType = model.Vip
  275. }
  276. oatime, err = time.ParseInLocation(model.TimeFormatSec, ovip.AnnualVipOverdueTime, time.Local)
  277. if err != nil {
  278. oatime = zeroTime
  279. err = nil
  280. }
  281. if ovip.Type == model.AnnualVip && oatime.After(now) {
  282. ovType = model.AnnualVip
  283. }
  284. if ovType == model.Vip && nvType == model.AnnualVip {
  285. // normal vip -> annual vip
  286. salaryType = model.VipSupplyType
  287. }
  288. // short vip -> normal vip
  289. recentTime := parseTime(ovip.RecentTime)
  290. otime := parseTime(ovip.OverdueTime)
  291. days := otime.Sub(recentTime).Hours() / model.DayOfHour
  292. if days < model.VipDaysMonth {
  293. //check open days is enough 31
  294. days := ntime.Sub(now).Hours() / model.DayOfHour
  295. if days < model.VipDaysMonth {
  296. log.Info("cur user not enough send coupon (%+v)", nvip)
  297. return
  298. }
  299. if nvType == model.Vip {
  300. // expire vip -> vip
  301. salaryType = model.NormalVipSalaryType
  302. } else if nvType == model.AnnualVip {
  303. // expire vip -> annual vip
  304. salaryType = model.AnnualVipSalaryType
  305. }
  306. }
  307. }
  308. switch salaryType {
  309. case model.NormalVipSalaryType, model.AnnualVipSalaryType, model.VipSupplyType:
  310. if err = s.salaryCoupon(c, int64(nvip.Mid), salaryType, int8(nvType), dv, model.CouponSalaryAtonce); err != nil {
  311. err = errors.Wrapf(err, "salaryCoupon mid(%d)(%v)", int64(nvip.Mid), nvip)
  312. }
  313. }
  314. return
  315. }
  316. // judgeVipExpire judge vip is expire.
  317. func (s *Service) judgeVipExpire(c context.Context, v *model.VipUserInfoMsg) (expire bool, err error) {
  318. var (
  319. now = time.Now()
  320. overdueTime time.Time
  321. zeroTime = now.AddDate(-10, 0, 0)
  322. )
  323. if v.Status != model.VipStatusNotOverTime && v.Status != model.VipStatusFrozen {
  324. expire = true
  325. return
  326. }
  327. overdueTime, err = time.ParseInLocation(model.TimeFormatSec, v.OverdueTime, time.Local)
  328. if err != nil {
  329. log.Error("time.ParseInLocation error(%v)", errors.Wrapf(err, "time(%s)", v.OverdueTime))
  330. overdueTime = zeroTime
  331. err = nil
  332. }
  333. if overdueTime.Before(now) {
  334. expire = true
  335. return
  336. }
  337. return
  338. }