av_breach.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. package income
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "strconv"
  7. "time"
  8. upModel "go-common/app/admin/main/growup/model"
  9. model "go-common/app/admin/main/growup/model/income"
  10. "go-common/app/admin/main/growup/service"
  11. "go-common/library/database/sql"
  12. "go-common/library/log"
  13. xtime "go-common/library/time"
  14. "go-common/library/xstr"
  15. "golang.org/x/sync/errgroup"
  16. )
  17. // BreachList list
  18. func (s *Service) BreachList(c context.Context, mids, aids []int64, typ int, fromTime, toTime int64, reason string, from, limit int) (breachs []*model.AvBreach, total int, err error) {
  19. query := formatBreachQuery(mids, aids, typ, fromTime, toTime, reason)
  20. total, err = s.dao.BreachCount(c, query)
  21. if err != nil {
  22. log.Error("s.dao.GetBreachCount error(%v)", err)
  23. return
  24. }
  25. query = fmt.Sprintf("%s LIMIT %d,%d", query, from, limit)
  26. breachs, err = s.dao.ListArchiveBreach(c, query)
  27. if err != nil {
  28. log.Error("s.dao.ListArchiveBreach error(%v)", err)
  29. }
  30. mids = make([]int64, 0, len(breachs))
  31. for _, b := range breachs {
  32. mids = append(mids, b.MID)
  33. }
  34. nickname, err := s.dao.ListUpInfo(c, mids)
  35. for _, b := range breachs {
  36. b.Nickname = nickname[b.MID]
  37. }
  38. return
  39. }
  40. // BreachStatis statis
  41. func (s *Service) BreachStatis(c context.Context, mids, aids []int64, typ, groupType int, fromTime, toTime int64, reason string) (date interface{}, err error) {
  42. from := getDateByGroup(groupType, time.Unix(fromTime, 0))
  43. to := getDateByGroup(groupType, time.Unix(toTime, 0))
  44. query := formatBreachQuery(mids, aids, typ, from.Unix(), to.Unix(), reason)
  45. breachs, err := s.dao.ListArchiveBreach(c, query)
  46. if err != nil {
  47. log.Error("s.dao.ListArchiveBreach error(%v)", err)
  48. return
  49. }
  50. date = breachStatis(breachs, from, to, groupType)
  51. return
  52. }
  53. func breachStatis(breachs []*model.AvBreach, from, to time.Time, groupType int) interface{} {
  54. dateIncome := make(map[string]int64)
  55. dateUps := make(map[string]map[int64]struct{})
  56. for _, breach := range breachs {
  57. date := formatDateByGroup(breach.CDate.Time(), groupType)
  58. if _, ok := dateIncome[date]; ok {
  59. dateIncome[date] += breach.Money
  60. } else {
  61. dateIncome[date] = breach.Money
  62. }
  63. if _, ok := dateUps[date]; !ok {
  64. dateUps[date] = make(map[int64]struct{})
  65. }
  66. dateUps[date][breach.MID] = struct{}{}
  67. }
  68. income, counts, xAxis := []string{}, []int{}, []string{}
  69. // get result by date
  70. to = to.AddDate(0, 0, 1)
  71. for from.Before(to) {
  72. dateStr := formatDateByGroup(from, groupType)
  73. xAxis = append(xAxis, dateStr)
  74. if val, ok := dateIncome[dateStr]; ok {
  75. income = append(income, fmt.Sprintf("%.2f", float64(val)/float64(100)))
  76. counts = append(counts, len(dateUps[dateStr]))
  77. } else {
  78. income = append(income, "0")
  79. counts = append(counts, 0)
  80. }
  81. from = addDayByGroup(groupType, from)
  82. }
  83. return map[string]interface{}{
  84. "counts": counts,
  85. "incomes": income,
  86. "xaxis": xAxis,
  87. }
  88. }
  89. // ExportBreach export
  90. func (s *Service) ExportBreach(c context.Context, mids, aids []int64, typ int, fromTime, toTime int64, reason string, from, limit int) (res []byte, err error) {
  91. breachs, _, err := s.BreachList(c, mids, aids, typ, fromTime, toTime, reason, from, limit)
  92. if err != nil {
  93. log.Error("s.BreachList error(%v)", err)
  94. return
  95. }
  96. records := formatBreach(breachs)
  97. res, err = service.FormatCSV(records)
  98. if err != nil {
  99. log.Error("FormatCSV error(%v)")
  100. }
  101. return
  102. }
  103. func formatBreachQuery(mids, aids []int64, typ int, fromTime, toTime int64, reason string) (query string) {
  104. query = fmt.Sprintf("cdate >= '%s' AND cdate <= '%s'", time.Unix(fromTime, 0).Format(_layout), time.Unix(toTime, 0).Format(_layout))
  105. if typ != 4 {
  106. query = fmt.Sprintf("%s AND ctype = %d", query, typ)
  107. }
  108. if len(mids) > 0 {
  109. query = fmt.Sprintf("%s AND mid IN (%s)", query, xstr.JoinInts(mids))
  110. }
  111. if len(aids) > 0 {
  112. query = fmt.Sprintf("%s AND av_id IN (%s)", query, xstr.JoinInts(aids))
  113. }
  114. if reason != "" {
  115. query = fmt.Sprintf("%s AND reason = '%s'", query, reason)
  116. }
  117. return
  118. }
  119. // ArchiveBreach breach archive batch
  120. func (s *Service) ArchiveBreach(c context.Context, typ int, aids []int64, mid int64, reason string, operator string) (err error) {
  121. count, err := s.dao.BreachCount(c, fmt.Sprintf("av_id in (%s) AND cdate = '%s'", xstr.JoinInts(aids), time.Now().Format(_layout)))
  122. if err != nil {
  123. log.Error("s.dao.AvBreachCount error(%v)", err)
  124. return
  125. }
  126. if count > 0 {
  127. err = fmt.Errorf("有稿件已被扣除")
  128. return
  129. }
  130. return s.avBreach(c, typ, aids, mid, reason, operator)
  131. }
  132. func assembleAvBreach(aids []int64, mid int64, ctype int, reason string, breach map[int64]int64, upload map[int64]string) (vals string) {
  133. var buf bytes.Buffer
  134. for _, aid := range aids {
  135. buf.WriteString("(")
  136. buf.WriteString(strconv.FormatInt(aid, 10))
  137. buf.WriteByte(',')
  138. buf.WriteString(strconv.FormatInt(mid, 10))
  139. buf.WriteByte(',')
  140. buf.WriteString("'" + time.Now().Format(_layout) + "'")
  141. buf.WriteByte(',')
  142. buf.WriteString(strconv.FormatInt(breach[aid], 10))
  143. buf.WriteByte(',')
  144. buf.WriteString(strconv.Itoa(ctype))
  145. buf.WriteByte(',')
  146. buf.WriteString("\"" + reason + "\"")
  147. buf.WriteByte(',')
  148. buf.WriteString("'" + upload[aid] + "'")
  149. buf.WriteString(")")
  150. buf.WriteByte(',')
  151. }
  152. if buf.Len() > 0 {
  153. buf.Truncate(buf.Len() - 1)
  154. }
  155. vals = buf.String()
  156. buf.Reset()
  157. return
  158. }
  159. // AvBreach av breach from av_income
  160. func (s *Service) avBreach(c context.Context, ctype int, aids []int64, mid int64, reason string, operator string) (err error) {
  161. archives, withdrawMonth, err := s.GetArchiveByUpAccount(c, ctype, aids, mid)
  162. if err != nil {
  163. log.Error("s.GetArchiveByUpAccount error(%v)", err)
  164. return
  165. }
  166. if len(archives) == 0 {
  167. return
  168. }
  169. preMonthBreach, thisMonthBreach, avBreach, avUpload := getBreachMoney(archives, withdrawMonth)
  170. tx, err := s.dao.BeginTran(c)
  171. if err != nil {
  172. log.Error("s.dao.BeginTran error(%v)", err)
  173. return
  174. }
  175. var eg errgroup.Group
  176. // insert av_breach
  177. eg.Go(func() (err error) {
  178. if _, err = s.dao.TxInsertAvBreach(tx, assembleAvBreach(aids, mid, ctype, reason, avBreach, avUpload)); err != nil {
  179. log.Error("s.TxInsertAvBreach error(%v)", err)
  180. tx.Rollback()
  181. }
  182. return
  183. })
  184. // update av breach pre state = 2
  185. eg.Go(func() (err error) {
  186. if _, err = s.dao.TxUpdateBreachPre(tx, aids, time.Now().Format(_layout)); err != nil {
  187. log.Error("s.TxUpdateBreachPre error(%v)", err)
  188. tx.Rollback()
  189. }
  190. return
  191. })
  192. // save av_black_list
  193. eg.Go(func() (err error) {
  194. if err = s.TxInsertAvBlacklist(c, tx, ctype, aids, mid, _avBreach, len(aids)); err != nil {
  195. log.Error("s.InsertAvBlacklist error(%v)", err)
  196. }
  197. return
  198. })
  199. // update up_account
  200. eg.Go(func() (err error) {
  201. if err = s.TxUpAccountBreach(c, tx, mid, preMonthBreach, thisMonthBreach); err != nil {
  202. log.Error("s.UpdateUpAccount error(%v)", err)
  203. }
  204. return
  205. })
  206. // update up credit score
  207. eg.Go(func() (err error) {
  208. if err = s.UpdateUpCredit(c, tx, ctype, mid, aids, operator); err != nil {
  209. log.Error("s.UpdateUpCredit error(%v)", err)
  210. }
  211. return
  212. })
  213. eg.Go(func() (err error) {
  214. if _, err = s.upDao.TxUpdateAvSpyState(tx, 1, aids); err != nil {
  215. tx.Rollback()
  216. log.Error("s.upDao.TxUpdateAvSpyState error(%v)", err)
  217. }
  218. return
  219. })
  220. if err = eg.Wait(); err != nil {
  221. log.Error("run eg.Wait error(%v)", err)
  222. return
  223. }
  224. if err = tx.Commit(); err != nil {
  225. log.Error("tx.Commit error")
  226. return
  227. }
  228. var business string
  229. switch ctype {
  230. case _video:
  231. business = "avid"
  232. case _column:
  233. business = "cv"
  234. case _bgm:
  235. business = "au"
  236. }
  237. for _, aid := range aids {
  238. err = s.msg.Send(c, "1_14_5",
  239. fmt.Sprintf("您的稿件 %s %d 违反创作激励计划规则。", business, aid),
  240. fmt.Sprintf("您的稿件 %s %d 因为%s原因被取消参加创作激励计划资格,已获得收入将被扣除。如有疑问,请联系客服。", business, aid, reason),
  241. []int64{mid},
  242. time.Now().Unix())
  243. if err != nil {
  244. log.Error("s.msg.Send error(%v)", err)
  245. return
  246. }
  247. }
  248. return
  249. }
  250. // UpdateUpCredit update up_info credit score
  251. func (s *Service) UpdateUpCredit(c context.Context, tx *sql.Tx, ctype int, mid int64, aids []int64, operator string) (err error) {
  252. score, err := s.upDao.CreditScore(c, mid)
  253. if err != nil {
  254. return
  255. }
  256. // insert credit_score_record
  257. creditRecord := &upModel.CreditRecord{
  258. MID: mid,
  259. OperateAt: xtime.Time(time.Now().Unix()),
  260. Operator: operator,
  261. Reason: 9,
  262. Deducted: 3 * len(aids),
  263. Remaining: score - 3*len(aids),
  264. }
  265. r1, err := s.upDao.TxInsertCreditRecord(tx, creditRecord)
  266. if err != nil {
  267. tx.Rollback()
  268. return
  269. }
  270. r2, err := s.upDao.TxUpdateCreditScore(tx, mid, score-3*len(aids))
  271. if err != nil {
  272. tx.Rollback()
  273. return
  274. }
  275. if r1 != r2 {
  276. tx.Rollback()
  277. return
  278. }
  279. return
  280. }
  281. // GetArchiveByUpAccount get archive income by withdraw date
  282. func (s *Service) GetArchiveByUpAccount(c context.Context, typ int, aids []int64, mid int64) (archives []*model.ArchiveIncome, withdrawMonth time.Month, err error) {
  283. archives = make([]*model.ArchiveIncome, 0)
  284. upAccount, err := s.dao.GetUpAccount(c, mid)
  285. if err != nil {
  286. if err == sql.ErrNoRows {
  287. err = nil
  288. return
  289. }
  290. log.Error("s.dao.GetUpAccount error(%v)", err)
  291. return
  292. }
  293. withdrawDateStr := upAccount.WithdrawDateVersion + "-01"
  294. withdrawDate, err := time.Parse(_layout, withdrawDateStr)
  295. if err != nil {
  296. log.Error("time.Parse error(%v)", err)
  297. return
  298. }
  299. withdrawMonth = withdrawDate.AddDate(0, 1, 0).Month()
  300. from, now := withdrawDate.AddDate(0, 1, 0).Format(_layout), time.Now().Format(_layout)
  301. query := ""
  302. switch typ {
  303. case _video:
  304. query = fmt.Sprintf("av_id in (%s)", xstr.JoinInts(aids))
  305. case _column:
  306. query = fmt.Sprintf("aid in (%s)", xstr.JoinInts(aids))
  307. case _bgm:
  308. query = fmt.Sprintf("sid in (%s)", xstr.JoinInts(aids))
  309. }
  310. archives, err = s.GetArchiveIncome(c, typ, query, from, now)
  311. if err != nil {
  312. log.Error("s.GetArchiveIncome error(%v)", err)
  313. }
  314. return
  315. }
  316. func getBreachMoney(archives []*model.ArchiveIncome, withdrawMonth time.Month) (int64, int64, map[int64]int64, map[int64]string) {
  317. var preMonthBreach, thisMonthBreach int64 = 0, 0
  318. avBreach := make(map[int64]int64)
  319. avUpload := make(map[int64]string)
  320. for _, arch := range archives {
  321. if arch.Date.Time().Month() == withdrawMonth {
  322. preMonthBreach += arch.Income
  323. } else {
  324. thisMonthBreach += arch.Income
  325. }
  326. avBreach[arch.AvID] += arch.Income
  327. avUpload[arch.AvID] = arch.UploadTime.Time().Format(_layout)
  328. }
  329. return preMonthBreach, thisMonthBreach, avBreach, avUpload
  330. }