360 lines
10 KiB
Go
360 lines
10 KiB
Go
package income
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"fmt"
|
||
"strconv"
|
||
"time"
|
||
|
||
upModel "go-common/app/admin/main/growup/model"
|
||
model "go-common/app/admin/main/growup/model/income"
|
||
"go-common/app/admin/main/growup/service"
|
||
|
||
"go-common/library/database/sql"
|
||
"go-common/library/log"
|
||
xtime "go-common/library/time"
|
||
"go-common/library/xstr"
|
||
|
||
"golang.org/x/sync/errgroup"
|
||
)
|
||
|
||
// BreachList list
|
||
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) {
|
||
query := formatBreachQuery(mids, aids, typ, fromTime, toTime, reason)
|
||
total, err = s.dao.BreachCount(c, query)
|
||
if err != nil {
|
||
log.Error("s.dao.GetBreachCount error(%v)", err)
|
||
return
|
||
}
|
||
query = fmt.Sprintf("%s LIMIT %d,%d", query, from, limit)
|
||
breachs, err = s.dao.ListArchiveBreach(c, query)
|
||
if err != nil {
|
||
log.Error("s.dao.ListArchiveBreach error(%v)", err)
|
||
}
|
||
|
||
mids = make([]int64, 0, len(breachs))
|
||
for _, b := range breachs {
|
||
mids = append(mids, b.MID)
|
||
}
|
||
nickname, err := s.dao.ListUpInfo(c, mids)
|
||
for _, b := range breachs {
|
||
b.Nickname = nickname[b.MID]
|
||
}
|
||
return
|
||
}
|
||
|
||
// BreachStatis statis
|
||
func (s *Service) BreachStatis(c context.Context, mids, aids []int64, typ, groupType int, fromTime, toTime int64, reason string) (date interface{}, err error) {
|
||
from := getDateByGroup(groupType, time.Unix(fromTime, 0))
|
||
to := getDateByGroup(groupType, time.Unix(toTime, 0))
|
||
query := formatBreachQuery(mids, aids, typ, from.Unix(), to.Unix(), reason)
|
||
breachs, err := s.dao.ListArchiveBreach(c, query)
|
||
if err != nil {
|
||
log.Error("s.dao.ListArchiveBreach error(%v)", err)
|
||
return
|
||
}
|
||
date = breachStatis(breachs, from, to, groupType)
|
||
return
|
||
}
|
||
|
||
func breachStatis(breachs []*model.AvBreach, from, to time.Time, groupType int) interface{} {
|
||
dateIncome := make(map[string]int64)
|
||
dateUps := make(map[string]map[int64]struct{})
|
||
for _, breach := range breachs {
|
||
date := formatDateByGroup(breach.CDate.Time(), groupType)
|
||
if _, ok := dateIncome[date]; ok {
|
||
dateIncome[date] += breach.Money
|
||
} else {
|
||
dateIncome[date] = breach.Money
|
||
}
|
||
if _, ok := dateUps[date]; !ok {
|
||
dateUps[date] = make(map[int64]struct{})
|
||
}
|
||
dateUps[date][breach.MID] = struct{}{}
|
||
}
|
||
|
||
income, counts, xAxis := []string{}, []int{}, []string{}
|
||
// get result by date
|
||
to = to.AddDate(0, 0, 1)
|
||
for from.Before(to) {
|
||
dateStr := formatDateByGroup(from, groupType)
|
||
xAxis = append(xAxis, dateStr)
|
||
if val, ok := dateIncome[dateStr]; ok {
|
||
income = append(income, fmt.Sprintf("%.2f", float64(val)/float64(100)))
|
||
counts = append(counts, len(dateUps[dateStr]))
|
||
} else {
|
||
income = append(income, "0")
|
||
counts = append(counts, 0)
|
||
}
|
||
from = addDayByGroup(groupType, from)
|
||
}
|
||
|
||
return map[string]interface{}{
|
||
"counts": counts,
|
||
"incomes": income,
|
||
"xaxis": xAxis,
|
||
}
|
||
}
|
||
|
||
// ExportBreach export
|
||
func (s *Service) ExportBreach(c context.Context, mids, aids []int64, typ int, fromTime, toTime int64, reason string, from, limit int) (res []byte, err error) {
|
||
breachs, _, err := s.BreachList(c, mids, aids, typ, fromTime, toTime, reason, from, limit)
|
||
if err != nil {
|
||
log.Error("s.BreachList error(%v)", err)
|
||
return
|
||
}
|
||
records := formatBreach(breachs)
|
||
res, err = service.FormatCSV(records)
|
||
if err != nil {
|
||
log.Error("FormatCSV error(%v)")
|
||
}
|
||
return
|
||
}
|
||
|
||
func formatBreachQuery(mids, aids []int64, typ int, fromTime, toTime int64, reason string) (query string) {
|
||
query = fmt.Sprintf("cdate >= '%s' AND cdate <= '%s'", time.Unix(fromTime, 0).Format(_layout), time.Unix(toTime, 0).Format(_layout))
|
||
if typ != 4 {
|
||
query = fmt.Sprintf("%s AND ctype = %d", query, typ)
|
||
}
|
||
if len(mids) > 0 {
|
||
query = fmt.Sprintf("%s AND mid IN (%s)", query, xstr.JoinInts(mids))
|
||
}
|
||
if len(aids) > 0 {
|
||
query = fmt.Sprintf("%s AND av_id IN (%s)", query, xstr.JoinInts(aids))
|
||
}
|
||
if reason != "" {
|
||
query = fmt.Sprintf("%s AND reason = '%s'", query, reason)
|
||
}
|
||
return
|
||
}
|
||
|
||
// ArchiveBreach breach archive batch
|
||
func (s *Service) ArchiveBreach(c context.Context, typ int, aids []int64, mid int64, reason string, operator string) (err error) {
|
||
count, err := s.dao.BreachCount(c, fmt.Sprintf("av_id in (%s) AND cdate = '%s'", xstr.JoinInts(aids), time.Now().Format(_layout)))
|
||
if err != nil {
|
||
log.Error("s.dao.AvBreachCount error(%v)", err)
|
||
return
|
||
}
|
||
if count > 0 {
|
||
err = fmt.Errorf("有稿件已被扣除")
|
||
return
|
||
}
|
||
return s.avBreach(c, typ, aids, mid, reason, operator)
|
||
}
|
||
|
||
func assembleAvBreach(aids []int64, mid int64, ctype int, reason string, breach map[int64]int64, upload map[int64]string) (vals string) {
|
||
var buf bytes.Buffer
|
||
for _, aid := range aids {
|
||
buf.WriteString("(")
|
||
buf.WriteString(strconv.FormatInt(aid, 10))
|
||
buf.WriteByte(',')
|
||
buf.WriteString(strconv.FormatInt(mid, 10))
|
||
buf.WriteByte(',')
|
||
buf.WriteString("'" + time.Now().Format(_layout) + "'")
|
||
buf.WriteByte(',')
|
||
buf.WriteString(strconv.FormatInt(breach[aid], 10))
|
||
buf.WriteByte(',')
|
||
buf.WriteString(strconv.Itoa(ctype))
|
||
buf.WriteByte(',')
|
||
buf.WriteString("\"" + reason + "\"")
|
||
buf.WriteByte(',')
|
||
buf.WriteString("'" + upload[aid] + "'")
|
||
buf.WriteString(")")
|
||
buf.WriteByte(',')
|
||
}
|
||
if buf.Len() > 0 {
|
||
buf.Truncate(buf.Len() - 1)
|
||
}
|
||
vals = buf.String()
|
||
buf.Reset()
|
||
return
|
||
}
|
||
|
||
// AvBreach av breach from av_income
|
||
func (s *Service) avBreach(c context.Context, ctype int, aids []int64, mid int64, reason string, operator string) (err error) {
|
||
archives, withdrawMonth, err := s.GetArchiveByUpAccount(c, ctype, aids, mid)
|
||
if err != nil {
|
||
log.Error("s.GetArchiveByUpAccount error(%v)", err)
|
||
return
|
||
}
|
||
if len(archives) == 0 {
|
||
return
|
||
}
|
||
preMonthBreach, thisMonthBreach, avBreach, avUpload := getBreachMoney(archives, withdrawMonth)
|
||
|
||
tx, err := s.dao.BeginTran(c)
|
||
if err != nil {
|
||
log.Error("s.dao.BeginTran error(%v)", err)
|
||
return
|
||
}
|
||
var eg errgroup.Group
|
||
// insert av_breach
|
||
eg.Go(func() (err error) {
|
||
if _, err = s.dao.TxInsertAvBreach(tx, assembleAvBreach(aids, mid, ctype, reason, avBreach, avUpload)); err != nil {
|
||
log.Error("s.TxInsertAvBreach error(%v)", err)
|
||
tx.Rollback()
|
||
}
|
||
return
|
||
})
|
||
|
||
// update av breach pre state = 2
|
||
eg.Go(func() (err error) {
|
||
if _, err = s.dao.TxUpdateBreachPre(tx, aids, time.Now().Format(_layout)); err != nil {
|
||
log.Error("s.TxUpdateBreachPre error(%v)", err)
|
||
tx.Rollback()
|
||
}
|
||
return
|
||
})
|
||
|
||
// save av_black_list
|
||
eg.Go(func() (err error) {
|
||
if err = s.TxInsertAvBlacklist(c, tx, ctype, aids, mid, _avBreach, len(aids)); err != nil {
|
||
log.Error("s.InsertAvBlacklist error(%v)", err)
|
||
}
|
||
return
|
||
})
|
||
// update up_account
|
||
eg.Go(func() (err error) {
|
||
if err = s.TxUpAccountBreach(c, tx, mid, preMonthBreach, thisMonthBreach); err != nil {
|
||
log.Error("s.UpdateUpAccount error(%v)", err)
|
||
}
|
||
return
|
||
})
|
||
// update up credit score
|
||
eg.Go(func() (err error) {
|
||
if err = s.UpdateUpCredit(c, tx, ctype, mid, aids, operator); err != nil {
|
||
log.Error("s.UpdateUpCredit error(%v)", err)
|
||
}
|
||
return
|
||
})
|
||
|
||
eg.Go(func() (err error) {
|
||
if _, err = s.upDao.TxUpdateAvSpyState(tx, 1, aids); err != nil {
|
||
tx.Rollback()
|
||
log.Error("s.upDao.TxUpdateAvSpyState error(%v)", err)
|
||
}
|
||
return
|
||
})
|
||
|
||
if err = eg.Wait(); err != nil {
|
||
log.Error("run eg.Wait error(%v)", err)
|
||
return
|
||
}
|
||
|
||
if err = tx.Commit(); err != nil {
|
||
log.Error("tx.Commit error")
|
||
return
|
||
}
|
||
|
||
var business string
|
||
switch ctype {
|
||
case _video:
|
||
business = "avid"
|
||
case _column:
|
||
business = "cv"
|
||
case _bgm:
|
||
business = "au"
|
||
}
|
||
|
||
for _, aid := range aids {
|
||
err = s.msg.Send(c, "1_14_5",
|
||
fmt.Sprintf("您的稿件 %s %d 违反创作激励计划规则。", business, aid),
|
||
fmt.Sprintf("您的稿件 %s %d 因为%s原因被取消参加创作激励计划资格,已获得收入将被扣除。如有疑问,请联系客服。", business, aid, reason),
|
||
[]int64{mid},
|
||
time.Now().Unix())
|
||
if err != nil {
|
||
log.Error("s.msg.Send error(%v)", err)
|
||
return
|
||
}
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// UpdateUpCredit update up_info credit score
|
||
func (s *Service) UpdateUpCredit(c context.Context, tx *sql.Tx, ctype int, mid int64, aids []int64, operator string) (err error) {
|
||
score, err := s.upDao.CreditScore(c, mid)
|
||
if err != nil {
|
||
return
|
||
}
|
||
// insert credit_score_record
|
||
creditRecord := &upModel.CreditRecord{
|
||
MID: mid,
|
||
OperateAt: xtime.Time(time.Now().Unix()),
|
||
Operator: operator,
|
||
Reason: 9,
|
||
Deducted: 3 * len(aids),
|
||
Remaining: score - 3*len(aids),
|
||
}
|
||
r1, err := s.upDao.TxInsertCreditRecord(tx, creditRecord)
|
||
if err != nil {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
|
||
r2, err := s.upDao.TxUpdateCreditScore(tx, mid, score-3*len(aids))
|
||
if err != nil {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
if r1 != r2 {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
return
|
||
}
|
||
|
||
// GetArchiveByUpAccount get archive income by withdraw date
|
||
func (s *Service) GetArchiveByUpAccount(c context.Context, typ int, aids []int64, mid int64) (archives []*model.ArchiveIncome, withdrawMonth time.Month, err error) {
|
||
archives = make([]*model.ArchiveIncome, 0)
|
||
upAccount, err := s.dao.GetUpAccount(c, mid)
|
||
if err != nil {
|
||
if err == sql.ErrNoRows {
|
||
err = nil
|
||
return
|
||
}
|
||
log.Error("s.dao.GetUpAccount error(%v)", err)
|
||
return
|
||
}
|
||
|
||
withdrawDateStr := upAccount.WithdrawDateVersion + "-01"
|
||
withdrawDate, err := time.Parse(_layout, withdrawDateStr)
|
||
if err != nil {
|
||
log.Error("time.Parse error(%v)", err)
|
||
return
|
||
}
|
||
withdrawMonth = withdrawDate.AddDate(0, 1, 0).Month()
|
||
from, now := withdrawDate.AddDate(0, 1, 0).Format(_layout), time.Now().Format(_layout)
|
||
query := ""
|
||
switch typ {
|
||
case _video:
|
||
query = fmt.Sprintf("av_id in (%s)", xstr.JoinInts(aids))
|
||
case _column:
|
||
query = fmt.Sprintf("aid in (%s)", xstr.JoinInts(aids))
|
||
case _bgm:
|
||
query = fmt.Sprintf("sid in (%s)", xstr.JoinInts(aids))
|
||
}
|
||
archives, err = s.GetArchiveIncome(c, typ, query, from, now)
|
||
if err != nil {
|
||
log.Error("s.GetArchiveIncome error(%v)", err)
|
||
}
|
||
return
|
||
}
|
||
|
||
func getBreachMoney(archives []*model.ArchiveIncome, withdrawMonth time.Month) (int64, int64, map[int64]int64, map[int64]string) {
|
||
var preMonthBreach, thisMonthBreach int64 = 0, 0
|
||
avBreach := make(map[int64]int64)
|
||
avUpload := make(map[int64]string)
|
||
for _, arch := range archives {
|
||
if arch.Date.Time().Month() == withdrawMonth {
|
||
preMonthBreach += arch.Income
|
||
} else {
|
||
thisMonthBreach += arch.Income
|
||
}
|
||
avBreach[arch.AvID] += arch.Income
|
||
avUpload[arch.AvID] = arch.UploadTime.Time().Format(_layout)
|
||
}
|
||
return preMonthBreach, thisMonthBreach, avBreach, avUpload
|
||
}
|