Plan stuff. Log stuff.
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

4 years ago
  1. package services
  2. import (
  3. "context"
  4. "github.com/gisle/stufflog/database"
  5. "github.com/gisle/stufflog/models"
  6. "github.com/gisle/stufflog/slerrors"
  7. "time"
  8. )
  9. // ScoringService scores activities. It cares not for users.
  10. type ScoringService struct {
  11. db database.Database
  12. }
  13. func (s *ScoringService) ScoreOne(ctx context.Context, period models.Period, log models.PeriodLog) (*models.Score, error) {
  14. return s.scoreOne(ctx, period, log)
  15. }
  16. func (s *ScoringService) scoreOne(ctx context.Context, period models.Period, log models.PeriodLog) (*models.Score, error) {
  17. goal := period.Goal(log.GoalID)
  18. if goal == nil {
  19. return nil, slerrors.NotFound("Goal")
  20. }
  21. activity, err := s.db.Activities().FindID(ctx, goal.ActivityID)
  22. if err != nil || activity.UserID != period.UserID {
  23. return nil, slerrors.NotFound("Goal's Activity")
  24. }
  25. subActivity := activity.SubActivity(log.SubActivityID)
  26. if subActivity == nil {
  27. return nil, slerrors.NotFound("Goal's Sub-Activity")
  28. }
  29. score := models.Score{
  30. ActivityScore: subActivity.Value,
  31. Amount: log.Amount,
  32. }
  33. if log.SubGoalID != "" {
  34. subGoal := goal.SubGoal(log.SubGoalID)
  35. if subGoal == nil {
  36. return nil, slerrors.NotFound("Sub-Goal")
  37. }
  38. multiplier := subGoal.Multiplier
  39. score.SubGoalMultiplier = &multiplier
  40. }
  41. if activity.DailyBonus > 0 {
  42. isFirst := true
  43. for _, log2 := range period.Logs {
  44. if log2.Date.Local().Truncate(time.Hour*24) != log.Date.Local().Truncate(time.Hour*24) {
  45. continue
  46. }
  47. if log2.ID == log.ID {
  48. break
  49. }
  50. if log2.GoalID == log.GoalID {
  51. isFirst = false
  52. break
  53. }
  54. }
  55. if isFirst {
  56. score.DailyBonus = activity.DailyBonus
  57. }
  58. }
  59. score.Calc()
  60. return &score, nil
  61. }
  62. func (s *ScoringService) ScoreAll(ctx context.Context, period models.Period) (*models.Period, error) {
  63. period = *period.Copy()
  64. for i, log := range period.Logs {
  65. score, err := s.scoreOne(ctx, period, log)
  66. if err != nil {
  67. return nil, err
  68. }
  69. period.Logs[i].Score = score
  70. }
  71. err := s.db.Periods().Insert(ctx, period)
  72. if err != nil {
  73. return nil, err
  74. }
  75. return &period, nil
  76. }
  77. func NewScoringService(db database.Database) *ScoringService {
  78. return &ScoringService{db: db}
  79. }