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.
680 lines
14 KiB
680 lines
14 KiB
package service |
|
|
|
import ( |
|
"context" |
|
"crypto/md5" |
|
"encoding/hex" |
|
"fmt" |
|
"math" |
|
"math/rand" |
|
"time" |
|
|
|
"go-common/app/admin/main/vip/model" |
|
"go-common/library/database/sql" |
|
"go-common/library/ecode" |
|
"go-common/library/log" |
|
xtime "go-common/library/time" |
|
|
|
"github.com/pkg/errors" |
|
) |
|
|
|
// QueryPool query pool |
|
func (s *Service) QueryPool(c context.Context, r *model.ResoucePoolBo) (res []*model.VipResourcePool, count int, err error) { |
|
var ( |
|
batch *model.VipResourceBatch |
|
PN int |
|
PS int |
|
) |
|
PN = r.PN |
|
PS = r.PS |
|
|
|
if batch, err = s.dao.SelBatchRow(c, r.BatchID); err != nil { |
|
return |
|
} |
|
if r.BatchID != 0 { |
|
r.ID = -1 |
|
} |
|
|
|
if batch != nil { |
|
r.ID = batch.PoolID |
|
} |
|
|
|
if count, err = s.dao.SelCountPool(c, r); err != nil || count == 0 { |
|
return |
|
} |
|
if res, err = s.dao.SelPool(c, r, PN, PS); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
// PoolInfo pool info |
|
func (s *Service) PoolInfo(c context.Context, id int) (res *model.VipResourcePool, err error) { |
|
if res, err = s.dao.SelPoolRow(c, id); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
// AddPool . |
|
func (s *Service) AddPool(c context.Context, r *model.ResoucePoolBo) (err error) { |
|
var ( |
|
p *model.VipResourcePool |
|
) |
|
if err = s.verificationPool(r); err != nil { |
|
return |
|
} |
|
if p, err = s.dao.SelPoolByName(c, r.PoolName); err != nil { |
|
return |
|
} |
|
if p != nil { |
|
err = ecode.VipPoolNameExitErr |
|
return |
|
} |
|
if _, err = s.dao.AddPool(c, r); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) verificationPool(r *model.ResoucePoolBo) (err error) { |
|
var ( |
|
business *model.VipBusinessInfo |
|
) |
|
if len(r.PoolName) == 0 { |
|
err = ecode.VipPoolNameErr |
|
return |
|
} |
|
if len(r.Reason) == 0 { |
|
err = ecode.VipPoolReasonErr |
|
return |
|
} |
|
if r.StartTime <= 0 { |
|
err = ecode.VipPoolStartTimeErr |
|
return |
|
} |
|
if r.EndTime <= 0 { |
|
err = ecode.VipPoolEndTimeErr |
|
return |
|
} |
|
if r.EndTime < r.StartTime { |
|
err = ecode.VipPoolValidityTimeErr |
|
return |
|
} |
|
|
|
if business, err = s.dao.SelBusiness(context.TODO(), r.BusinessID); err != nil { |
|
return |
|
} |
|
if business == nil { |
|
err = ecode.VipBusinessNotExitErr |
|
return |
|
} |
|
return |
|
} |
|
|
|
// UpdatePool . |
|
func (s *Service) UpdatePool(c context.Context, r *model.ResoucePoolBo) (err error) { |
|
var ( |
|
pool *model.VipResourcePool |
|
p *model.VipResourcePool |
|
batchs []*model.VipResourceBatch |
|
) |
|
if err = s.verificationPool(r); err != nil { |
|
return |
|
} |
|
if pool, err = s.dao.SelPoolRow(c, r.ID); err != nil { |
|
return |
|
} |
|
if pool == nil { |
|
err = ecode.VipPoolIDErr |
|
return |
|
} |
|
if p, err = s.dao.SelPoolByName(c, r.PoolName); err != nil { |
|
return |
|
} |
|
if p != nil && pool.PoolName != p.PoolName { |
|
err = ecode.VipPoolNameExitErr |
|
return |
|
} |
|
if batchs, err = s.dao.SelBatchRows(context.TODO(), r.ID); err != nil { |
|
return |
|
} |
|
for _, v := range batchs { |
|
if !(r.StartTime <= v.StartTime && r.EndTime >= v.EndTime) { |
|
err = ecode.VipPoolValidityTimeErr |
|
return |
|
} |
|
} |
|
if _, err = s.dao.UpdatePool(c, r); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
// BatchInfo . |
|
func (s *Service) BatchInfo(c context.Context, id int) (res *model.VipResourceBatch, err error) { |
|
if res, err = s.dao.SelBatchRow(c, id); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
// BatchInfoOfPool . |
|
func (s *Service) BatchInfoOfPool(c context.Context, poolID int) (res []*model.VipResourceBatch, err error) { |
|
if res, err = s.dao.SelBatchRows(c, poolID); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
// AddBatch . |
|
func (s *Service) AddBatch(c context.Context, r *model.ResouceBatchBo) (err error) { |
|
if err = s.verificationBatch(r); err != nil { |
|
return |
|
} |
|
r.SurplusCount = r.Count |
|
if _, err = s.dao.AddBatch(c, r); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
// UpdateBatch . |
|
func (s *Service) UpdateBatch(c context.Context, id, increment int, startTime, endTime xtime.Time) (err error) { |
|
var ( |
|
batch *model.VipResourceBatch |
|
r = new(model.ResouceBatchBo) |
|
) |
|
r.ID = id |
|
r.StartTime = startTime |
|
r.EndTime = endTime |
|
|
|
if batch, err = s.dao.SelBatchRow(c, id); err != nil { |
|
return |
|
} |
|
if batch == nil { |
|
err = ecode.VipBatchIDErr |
|
return |
|
} |
|
r.PoolID = batch.PoolID |
|
if err = s.verifBatchTime(r); err != nil { |
|
return |
|
} |
|
if increment < 0 { |
|
err = ecode.VipBatchPlusResouceErr |
|
return |
|
} |
|
if batch.Count+increment > math.MaxInt32 || batch.Count+increment < 0 { |
|
err = ecode.VipBatchCountErr |
|
return |
|
} |
|
batch.Count += increment |
|
batch.SurplusCount += increment |
|
batch.StartTime = r.StartTime |
|
batch.EndTime = r.EndTime |
|
ver := batch.Ver |
|
batch.Ver++ |
|
if _, err = s.dao.UpdateBatch(c, batch, ver); err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) verifBatchTime(r *model.ResouceBatchBo) (err error) { |
|
var ( |
|
pool *model.VipResourcePool |
|
) |
|
if pool, err = s.dao.SelPoolRow(context.TODO(), r.PoolID); err != nil { |
|
return |
|
} |
|
if pool == nil { |
|
err = ecode.VipPoolIDErr |
|
return |
|
} |
|
|
|
if pool.StartTime > r.StartTime || pool.EndTime < r.EndTime { |
|
err = ecode.VipPoolValidityTimeErr |
|
return |
|
} |
|
return |
|
} |
|
func (s *Service) verificationBatch(r *model.ResouceBatchBo) (err error) { |
|
|
|
if r.Unit <= 0 || r.Unit > 3660 { |
|
err = ecode.VipBatchUnitErr |
|
return |
|
} |
|
if r.Count <= 0 { |
|
err = ecode.VipBatchCountErr |
|
return |
|
} |
|
if err = s.verifBatchTime(r); err != nil { |
|
return |
|
} |
|
return |
|
|
|
} |
|
|
|
// GrandResouce grand resouce mid |
|
func (s *Service) GrandResouce(c context.Context, remark string, batchID int64, mids []int, username string) (failMid []int, err error) { |
|
var ( |
|
batch *model.VipResourceBatch |
|
) |
|
if len(remark) == 0 { |
|
err = ecode.VipRemarkErr |
|
return |
|
} |
|
|
|
if batch, err = s.dao.SelBatchRow(c, int(batchID)); err != nil { |
|
return |
|
} |
|
if batch == nil { |
|
err = ecode.VipBatchIDErr |
|
return |
|
} |
|
if err = s.checkBatchValid(batch); err != nil { |
|
return |
|
} |
|
for _, v := range mids { |
|
if err = s.grandMidOfResouce(c, v, int(batchID), username, remark); err != nil { |
|
log.Error("GrandResouce grandMidOfResouce(mid:%v,batchID:%v,username:%v,remark:%v error(%v))", v, batchID, username, remark, err) |
|
failMid = append(failMid, v) |
|
|
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) grandMidOfResouce(c context.Context, mid, batchID int, username, remark string) (err error) { |
|
//var ( |
|
// batch *model.VipResourceBatch |
|
// tx *sql.Tx |
|
// a int64 |
|
// hv *inModel.HandlerVip |
|
//) |
|
//if batch, err = s.dao.SelBatchRow(c, batchID); err != nil { |
|
// return |
|
//} |
|
//if batch.SurplusCount-1 < 0 { |
|
// err = ecode.VipBatchNotEnoughErr |
|
// return |
|
//} |
|
//batch.DirectUseCount++ |
|
//batch.SurplusCount-- |
|
//ver := batch.Ver |
|
//batch.Ver++ |
|
//if tx, err = s.dao.BeginTran(context.TODO()); err != nil { |
|
// return |
|
//} |
|
//defer func() { |
|
// if err != nil { |
|
// if err = tx.Commit(); err != nil { |
|
// tx.Rollback() |
|
// } |
|
// } else { |
|
// tx.Rollback() |
|
// } |
|
//}() |
|
//if a, err = s.dao.UseBatch(tx, batch, ver); err != nil { |
|
// return |
|
//} |
|
//if a > 0 { |
|
// if hv, err = s.exchangeVip(context.TODO(), tx, int(mid), batch.ID, batch.Unit, remark, username); err != nil { |
|
// return |
|
// } |
|
// s.asyncBcoin(func() { |
|
// s.vipRPC.BcoinProcesserHandler(context.TODO(), hv) |
|
// }) |
|
//} |
|
return |
|
} |
|
|
|
func (s *Service) checkBatchValid(batch *model.VipResourceBatch) (err error) { |
|
var ( |
|
pool *model.VipResourcePool |
|
business *model.VipBusinessInfo |
|
ct = time.Now() |
|
) |
|
if !(batch.StartTime.Time().Unix() <= ct.Unix() && ct.Unix() <= batch.EndTime.Time().Unix()) { |
|
err = ecode.VipBatchTTLErr |
|
return |
|
} |
|
if pool, err = s.dao.SelPoolRow(context.TODO(), batch.PoolID); err != nil { |
|
return |
|
} |
|
if pool == nil { |
|
err = ecode.VipPoolIDErr |
|
return |
|
} |
|
if !(pool.StartTime.Time().Unix() <= ct.Unix() && ct.Unix() <= pool.EndTime.Time().Unix()) { |
|
err = ecode.VipPoolValidityTimeErr |
|
return |
|
} |
|
if business, err = s.dao.SelBusiness(context.TODO(), pool.BusinessID); err != nil { |
|
return |
|
} |
|
if business == nil { |
|
err = ecode.VipBusinessNotExitErr |
|
return |
|
} |
|
if business.Status == 1 { |
|
err = ecode.VipBusinessStatusErr |
|
return |
|
} |
|
return |
|
} |
|
|
|
// SaveBatchCode . |
|
func (s *Service) SaveBatchCode(c context.Context, arg *model.BatchCode) (err error) { |
|
var batchID int64 |
|
if arg.ID == 0 { |
|
if err = s.checkBatchCodeValid(c, arg); err != nil { |
|
return |
|
} |
|
arg.SurplusCount = arg.Count |
|
var tx *sql.Tx |
|
|
|
if tx, err = s.dao.BeginTran(c); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
defer func() { |
|
if err == nil { |
|
if err = tx.Commit(); err != nil { |
|
log.Error("commimt error(%+v)", err) |
|
} |
|
} else { |
|
tx.Rollback() |
|
} |
|
}() |
|
|
|
arg.Status = 1 |
|
if batchID, err = s.dao.TxAddBatchCode(tx, arg); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
|
|
if err = s.createCode(tx, batchID, int(arg.Count)); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
|
|
} else { |
|
var ( |
|
bc *model.BatchCode |
|
bc1 *model.BatchCode |
|
) |
|
if bc, err = s.dao.SelBatchCodeID(c, arg.ID); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if bc == nil { |
|
err = ecode.VipBatchIDErr |
|
return |
|
} |
|
if bc.BatchName != arg.BatchName { |
|
if bc1, err = s.dao.SelBatchCodeName(c, arg.BatchName); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if bc1 != nil { |
|
err = ecode.VipBatchCodeNameErr |
|
return |
|
} |
|
} |
|
bc.BatchName = arg.BatchName |
|
bc.Reason = arg.Reason |
|
bc.Price = arg.Price |
|
bc.Contacts = arg.Contacts |
|
bc.ContactsNumber = arg.ContactsNumber |
|
bc.Type = arg.Type |
|
bc.MaxCount = arg.MaxCount |
|
bc.LimitDay = arg.LimitDay |
|
if _, err = s.dao.UpdateBatchCode(c, bc); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) checkBatchCodeValid(c context.Context, arg *model.BatchCode) (err error) { |
|
var ( |
|
b *model.VipBusinessInfo |
|
p *model.VipResourcePool |
|
bc *model.BatchCode |
|
) |
|
if b, err = s.BusinessInfo(c, int(arg.BusinessID)); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if b == nil { |
|
err = ecode.VipBusinessNotExitErr |
|
return |
|
} |
|
if p, err = s.PoolInfo(c, int(arg.PoolID)); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if p == nil { |
|
err = ecode.VipPoolIDErr |
|
return |
|
} |
|
|
|
if p.EndTime.Time().Before(arg.EndTime.Time()) || p.StartTime.Time().After(arg.StartTime.Time()) { |
|
err = ecode.VipPoolValidityTimeErr |
|
return |
|
} |
|
|
|
if bc, err = s.dao.SelBatchCodeName(c, arg.BatchName); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
|
|
if bc != nil { |
|
err = ecode.VipBatchCodeNameErr |
|
return |
|
} |
|
|
|
if arg.Unit <= 0 || arg.Unit > 3660 { |
|
err = ecode.VipBatchUnitErr |
|
return |
|
} |
|
if arg.Count <= 0 || arg.Count > 200000 { |
|
err = ecode.VipBatchCodeCountErr |
|
} |
|
if arg.Price > 10000 || arg.Price < 0 { |
|
err = ecode.VipBatchPriceErr |
|
return |
|
} |
|
return |
|
} |
|
|
|
// FrozenCode . |
|
func (s *Service) FrozenCode(c context.Context, codeID int64, status int8) (err error) { |
|
var ( |
|
code *model.ResourceCode |
|
) |
|
if code, err = s.dao.SelCodeID(c, codeID); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if code == nil { |
|
err = ecode.VipCodeIDErr |
|
return |
|
} |
|
code.Status = status |
|
if _, err = s.dao.UpdateCode(c, codeID, status); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
|
|
return |
|
} |
|
|
|
// FrozenBatchCode . |
|
func (s *Service) FrozenBatchCode(c context.Context, BatchCodeID int64, status int8) (err error) { |
|
var bc *model.BatchCode |
|
if bc, err = s.dao.SelBatchCodeID(c, BatchCodeID); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if bc == nil { |
|
err = ecode.VipBatchIDErr |
|
return |
|
} |
|
bc.Status = status |
|
|
|
if _, err = s.dao.UpdateBatchCode(c, bc); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) createCode(tx *sql.Tx, batchCodeID int64, size int) (err error) { |
|
var ( |
|
hash = md5.New() |
|
batchSize = 2000 |
|
codes = make([]*model.ResourceCode, 0) |
|
) |
|
|
|
for i := 1; i <= size; i++ { |
|
unix := time.Now().UnixNano() |
|
key := fmt.Sprintf("%v,%v,%v,%v", unix, batchCodeID, i, rand.Intn(10000000)) |
|
hash.Write([]byte(key)) |
|
sum := hash.Sum(nil) |
|
code := hex.EncodeToString(sum) |
|
code = code[8:24] |
|
r := new(model.ResourceCode) |
|
r.Code = code |
|
r.Status = model.NOTUSER |
|
r.BatchCodeID = batchCodeID |
|
codes = append(codes, r) |
|
if i%batchSize == 0 || i == size { |
|
if err = s.dao.BatchAddCode(tx, codes); err != nil { |
|
log.Error("batch add code %+v", err) |
|
return |
|
} |
|
codes = make([]*model.ResourceCode, 0) |
|
} |
|
} |
|
return |
|
} |
|
|
|
// SelBatchCodes . |
|
func (s *Service) SelBatchCodes(c context.Context, batchIDs []int64) (res []*model.BatchCode, err error) { |
|
if res, err = s.dao.SelBatchCodes(c, batchIDs); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
return |
|
} |
|
|
|
// SelCode . |
|
func (s *Service) SelCode(c context.Context, arg *model.ArgCode, username string, curID int64, ps int) (res []*model.CodeVo, cursor int64, pre int64, err error) { |
|
var ( |
|
codes []*model.ResourceCode |
|
batchIDs []int64 |
|
batchMap = make(map[int64]*model.BatchCode) |
|
batchCodes []*model.BatchCode |
|
linkmap map[int64]int64 |
|
) |
|
if linkmap, err = s.dao.GetSelCode(c, username); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
fmt.Printf("cur link map(%+v) \n", linkmap) |
|
if len(linkmap) == 0 { |
|
linkmap = make(map[int64]int64) |
|
} |
|
if codes, err = s.dao.SelCode(c, arg, curID, ps); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if len(codes) > 0 { |
|
cursor = codes[len(codes)-1].ID |
|
} else { |
|
return |
|
} |
|
|
|
linkmap[cursor] = curID |
|
pre = linkmap[curID] |
|
if err = s.dao.SetSelCode(c, username, linkmap); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
for _, v := range codes { |
|
batchIDs = append(batchIDs, v.BatchCodeID) |
|
} |
|
if batchCodes, err = s.dao.SelBatchCodes(c, batchIDs); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
for _, v := range batchCodes { |
|
batchMap[v.ID] = v |
|
} |
|
for _, v := range codes { |
|
r := new(model.CodeVo) |
|
r.ID = v.ID |
|
r.BatchCodeID = v.BatchCodeID |
|
r.Mid = v.Mid |
|
r.Ctime = v.Ctime |
|
r.Code = v.Code |
|
r.Status = v.Status |
|
r.UseTime = v.UseTime |
|
batchCode := batchMap[v.BatchCodeID] |
|
if batchCode == nil { |
|
err = ecode.VipBatchIDErr |
|
res = nil |
|
return |
|
} |
|
r.Unit = batchCode.Unit |
|
r.BatchName = batchCode.BatchName |
|
r.BatchStatus = batchCode.Status |
|
r.StartTime = batchCode.StartTime |
|
r.EndTime = batchCode.EndTime |
|
res = append(res, r) |
|
} |
|
|
|
return |
|
} |
|
|
|
// ExportCode . |
|
func (s *Service) ExportCode(c context.Context, batchID int64) (codes []string, err error) { |
|
var ( |
|
rc []*model.ResourceCode |
|
curID int64 |
|
ps = 2000 |
|
) |
|
arg := new(model.ArgCode) |
|
arg.BatchCodeID = batchID |
|
arg.Status = model.NOTUSER |
|
for { |
|
if rc, err = s.dao.SelCode(c, arg, curID, ps); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if len(rc) == 0 { |
|
return |
|
} |
|
for _, v := range rc { |
|
codes = append(codes, v.Code) |
|
} |
|
curID = rc[len(rc)-1].ID |
|
} |
|
|
|
} |
|
|
|
// SelBatchCode . |
|
func (s *Service) SelBatchCode(c context.Context, arg *model.ArgBatchCode, pn, ps int) (res []*model.BatchCode, total int64, err error) { |
|
if total, err = s.dao.SelBatchCodeCount(c, arg); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
if res, err = s.dao.SelBatchCode(c, arg, pn, ps); err != nil { |
|
err = errors.WithStack(err) |
|
return |
|
} |
|
return |
|
}
|
|
|