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.
98 lines
2.1 KiB
98 lines
2.1 KiB
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}
|
|
}
|