package stakepoint import ( "context" "errors" "github.com/shopspring/decimal" "github.com/zeromicro/go-zero/core/stores/sqlx" "nova_task/internal/consts" "nova_task/internal/model" "nova_task/internal/pkg/errs" "nova_task/internal/pkg/utils" "time" "nova_task/internal/svc" "nova_task/internal/types" "github.com/zeromicro/go-zero/core/logx" ) type StakePointLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } // 质押积分操作 func NewStakePointLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StakePointLogic { return &StakePointLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *StakePointLogic) StakePoint(req *types.StakePointReq) error { uid := utils.GetUidUint(l.ctx) r, err := l.svcCtx.RoleModel.FindOneByRoleId(l.ctx, req.RoleID) if err != nil { if errors.Is(err, model.ErrNotFound) { return errs.New(errs.ErrRoleNotFound, "role not exist") } l.Errorw("find role error", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrDatabaseOperate, err) } u, err := l.svcCtx.UserModel.FindOneByEmail(l.ctx, r.Account) if err != nil { if errors.Is(err, model.ErrNotFound) { return errs.New(errs.ErrUserNotFound, "user not found") } l.Errorw("find user error", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrDatabaseOperate, err) } if u.Id != uid { return errs.New(errs.ErrRoleNotFound, "role not exist") } lv, err := l.svcCtx.StakePointConfigModel.FindOne(l.ctx, uint(req.LevelId)) if err != nil { if errors.Is(err, model.ErrNotFound) { return errs.New(errs.ErrPointLevelConfigNotFound, "stake point level config not found") } return errs.New(errs.ErrDatabaseOperate, err) } clv, err := l.svcCtx.StakePointsModel.FindCurrentLevel(l.ctx, req.RoleID) if err != nil && !errors.Is(err, model.ErrNotFound) { l.Errorw("find current level error", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrDatabaseOperate, err) } start := time.Now() end := start.Add(time.Duration(lv.Days.Mul(decimal.NewFromInt(int64(time.Hour * 24))).IntPart())) switch req.Action { case 1: if err == nil { return errs.New(errs.ErrPointsStakeExist, "stake points exist") } err = l.svcCtx.DBConn.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error { err = l.svcCtx.AddUserAssetWithSession(ctx, session, uid, req.RoleID, consts.AssetType_Points, "", decimal.NewFromInt(int64(-lv.Points)), "stake points", 0, 0, false) if err != nil { return err } _, err = l.svcCtx.StakePointsModel.WithSession(session).Insert(ctx, &model.NhStakePoints{ Uid: uid, RoleId: uint64(req.RoleID), LevelId: lv.Id, Level: lv.Level, Points: lv.Points, StartTime: start, EndTime: end, Status: model.PointsStakeStatusStaking, }) if err != nil { return errs.New(errs.ErrDatabaseOperate, err) } _, err = l.svcCtx.StakePointsLogModel.WithSession(session).Insert(ctx, &model.NhStakePointsLog{ Uid: uid, RoleId: uint64(req.RoleID), LevelId: lv.Id, Level: lv.Level, Points: int(lv.Points), Action: 1, }) if err != nil { l.Errorw("stake points log error", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrDatabaseOperate, err) } _, err := l.svcCtx.GameAction(ctx, req.RoleID, consts.GameActionStakePoints, map[string]any{ "level": lv.Level, "operation": req.Action, "start_time": start.Unix(), "end_time": end.Unix(), "renew_times": 0, }) return err }) if err != nil { l.Errorw("积分质押", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrInternalServer, err) } case 2: if err != nil { l.Errorw("用户在未质押的情况下进行升级", logx.Field("uid", uid), logx.Field("role_id", req.RoleID)) return errs.New(errs.ErrPointStakeNotExist, "stake points not exist") } clvConfig, err := l.svcCtx.StakePointConfigModel.FindOne(l.ctx, clv.LevelId) if err != nil { if errors.Is(err, model.ErrNotFound) { return errs.New(errs.ErrPointLevelConfigNotFound, "current stake point level config not found") } return errs.New(errs.ErrDatabaseOperate, err) } if lv.Level <= clvConfig.Level { return errs.New(errs.ErrPointsStakeLevelNotAllow, "Upgraded pledge credit bracket must be higher than current bracket") } // 已续约,不可升级 if clv.Status != model.PointsStakeStatusStaking { return errs.New(errs.ErrPointsStakeHasRenew, "Current stake has renew") } err = l.svcCtx.DBConn.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error { points := lv.Points - clvConfig.Points err = l.svcCtx.AddUserAssetWithSession(ctx, session, uid, req.RoleID, consts.AssetType_Points, "", decimal.NewFromInt(int64(-points)), "stake points", 0, 0, false) if err != nil { return err } clv.Status = model.PointsStakeStatusUpgraded clv.EndTime = start spm := l.svcCtx.StakePointsModel.WithSession(session) err := spm.Update(ctx, clv) if err != nil { return errs.New(errs.ErrDatabaseOperate, err) } end = start.Add(time.Duration(lv.Days.Mul(decimal.NewFromInt(int64(time.Hour*24))).IntPart()) - start.Sub(clv.StartTime)) _, err = spm.Insert(ctx, &model.NhStakePoints{ Uid: uid, RoleId: uint64(req.RoleID), LevelId: lv.Id, Level: lv.Level, Points: lv.Points, StartTime: start, EndTime: end, Status: model.PointsStakeStatusStaking, }) if err != nil { return errs.New(errs.ErrDatabaseOperate, err) } _, err = l.svcCtx.StakePointsLogModel.WithSession(session).Insert(ctx, &model.NhStakePointsLog{ Uid: uid, RoleId: uint64(req.RoleID), LevelId: lv.Id, Level: lv.Level, Points: int(points), Action: 2, }) if err != nil { l.Errorw("stake points log error", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrDatabaseOperate, err) } _, err = l.svcCtx.GameAction(ctx, req.RoleID, consts.GameActionStakePoints, map[string]any{ "level": lv.Level, "operation": req.Action, "start_time": start.Unix(), "end_time": end.Unix(), "renew_times": 0, }) return err }) if err != nil { l.Errorw("积分质押升级失败", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrInternalServer, err) } case 3: if err != nil { l.Errorw("用户在未质押的情况下进行续约", logx.Field("uid", uid), logx.Field("role_id", req.RoleID)) return errs.New(errs.ErrPointStakeNotExist, "stake points not exist") } clvConfig, err := l.svcCtx.StakePointConfigModel.FindOne(l.ctx, clv.LevelId) if err != nil { if errors.Is(err, model.ErrNotFound) { return errs.New(errs.ErrPointLevelConfigNotFound, "current stake point level config not found") } return errs.New(errs.ErrDatabaseOperate, err) } // 续约等级不能小于当前等级 if lv.Level < clvConfig.Level { return errs.New(errs.ErrPointsStakeLevelNotAllow, "Renewal level cannot be lower than current level") } // 已续约,不可重复续约 if clv.Status != model.PointsStakeStatusStaking { return errs.New(errs.ErrPointsStakeHasRenew, "Current stake has renew") } // 判断是否在可续约时间范围内 if clv.EndTime.Sub(time.Now()) > time.Duration(clvConfig.RenewDays.Mul(decimal.NewFromInt(int64(time.Hour*24))).IntPart()) { return errs.New(errs.ErrPointsStakeNotInRenewTime, "Not within the renewal time frame") } // 判断是否属于续约期内 err = l.svcCtx.DBConn.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error { points := lv.Points - clvConfig.Points if points > 0 { err = l.svcCtx.AddUserAssetWithSession(ctx, session, uid, req.RoleID, consts.AssetType_Points, "", decimal.NewFromInt(int64(-points)), "stake points", 0, 0, false) if err != nil { return err } } clv.Status = model.PointsStakeStatusRenew spm := l.svcCtx.StakePointsModel.WithSession(session) err := spm.Update(ctx, clv) if err != nil { return errs.New(errs.ErrDatabaseOperate, err) } end = clv.EndTime.Add(time.Duration(lv.Days.Mul(decimal.NewFromInt(int64(time.Hour * 24))).IntPart())) _, err = spm.Insert(ctx, &model.NhStakePoints{ Uid: uid, RoleId: uint64(req.RoleID), LevelId: lv.Id, Level: lv.Level, Points: lv.Points, StartTime: clv.EndTime, EndTime: end, Status: model.PointsStakeStatusStaking, }) if err != nil { return errs.New(errs.ErrDatabaseOperate, err) } _, err = l.svcCtx.StakePointsLogModel.WithSession(session).Insert(ctx, &model.NhStakePointsLog{ Uid: uid, RoleId: uint64(req.RoleID), LevelId: lv.Id, Level: lv.Level, Points: int(points), Action: 3, }) if err != nil { l.Errorw("stake points log error", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrDatabaseOperate, err) } _, err = l.svcCtx.GameAction(ctx, req.RoleID, consts.GameActionStakePoints, map[string]any{ "level": lv.Level, "operation": req.Action, "start_time": start.Unix(), "end_time": end.Unix(), "renew_times": 0, }) return err }) if err != nil { l.Errorw("积分质押续期失败", logx.Field("err", err), logx.Field("role_id", req.RoleID), logx.Field("uid", uid), logx.Field("level_id", req.LevelId), logx.Field("action", req.Action)) return errs.New(errs.ErrInternalServer, err) } default: return errs.New(errs.ErrInvalidParam, "Invalid action") } return errs.Success() }