package services import ( "context" "github.com/gisle/stufflog/database" "github.com/gisle/stufflog/models" "github.com/gisle/stufflog/slerrors" "time" ) // ScoringService scores activities. It cares not for users. type ScoringService struct { db database.Database } func (s *ScoringService) ScoreOne(ctx context.Context, period models.Period, log models.PeriodLog) (*models.Score, error) { return s.scoreOne(ctx, period, log) } func (s *ScoringService) scoreOne(ctx context.Context, period models.Period, log models.PeriodLog) (*models.Score, error) { goal := period.Goal(log.GoalID) if goal == nil { return nil, slerrors.NotFound("Goal") } activity, err := s.db.Activities().FindID(ctx, goal.ActivityID) if err != nil || activity.UserID != period.UserID { return nil, slerrors.NotFound("Goal's Activity") } subActivity := activity.SubActivity(log.SubActivityID) if subActivity == nil { return nil, slerrors.NotFound("Goal's Sub-Activity") } score := models.Score{ ActivityScore: subActivity.Value, Amount: log.Amount, } if log.SubGoalID != "" { subGoal := goal.SubGoal(log.SubGoalID) if subGoal == nil { return nil, slerrors.NotFound("Sub-Goal") } multiplier := subGoal.Multiplier score.SubGoalMultiplier = &multiplier } if activity.DailyBonus > 0 { isFirst := true for _, log2 := range period.Logs { if log2.Date.Local().Truncate(time.Hour*24) != log.Date.Local().Truncate(time.Hour*24) { continue } if log2.ID == log.ID { break } if log2.GoalID == log.GoalID { isFirst = false break } } if isFirst { score.DailyBonus = activity.DailyBonus } } score.Calc() return &score, nil } func (s *ScoringService) ScoreAll(ctx context.Context, period models.Period) (*models.Period, error) { period = *period.Copy() for i, log := range period.Logs { score, err := s.scoreOne(ctx, period, log) if err != nil { return nil, err } period.Logs[i].Score = score } err := s.db.Periods().Insert(ctx, period) if err != nil { return nil, err } return &period, nil } func NewScoringService(db database.Database) *ScoringService { return &ScoringService{db: db} }