fix: resolve go vet error and dayStart logic in ComputeDailyTotals
- Fix 'string(d)' int-to-rune conversion in rpg_test.go by using fmt.Sprintf - Fix ComputeDailyTotals dayStart logic: initial state should be StateWorking when dayStart > 0, correctly counting work from dayStart to first out event - Update README project structure to reflect new domain/handler/repo layout - Implement missing achievements: rpg_pioneer (on RPG enable) and salary_setter (on first rate set) - Add tryUnlockAchievement helper to Handler
This commit is contained in:
68
internal/domain/totals.go
Normal file
68
internal/domain/totals.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package domain
|
||||
|
||||
import "sort"
|
||||
|
||||
// ComputeDailyTotals calculates the total work and break time from a list of events.
|
||||
func ComputeDailyTotals(events []Event, minBreakThreshold int64, dayStart, dayEnd int64) DailyTotals {
|
||||
if len(events) == 0 {
|
||||
return DailyTotals{}
|
||||
}
|
||||
|
||||
sorted := make([]Event, len(events))
|
||||
copy(sorted, events)
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return sorted[i].OccurredAt < sorted[j].OccurredAt
|
||||
})
|
||||
|
||||
var totalWork, totalBreak int64
|
||||
state := StateIdle
|
||||
var workStart, breakStart int64
|
||||
|
||||
if dayStart > 0 {
|
||||
state = StateWorking
|
||||
workStart = dayStart
|
||||
} else if sorted[0].EventType == "out" {
|
||||
state = StateOnBreak
|
||||
}
|
||||
|
||||
for _, e := range sorted {
|
||||
switch {
|
||||
case e.EventType == "in" && state == StateIdle:
|
||||
state = StateWorking
|
||||
workStart = e.OccurredAt
|
||||
case e.EventType == "in" && state == StateOnBreak:
|
||||
breakElapsed := e.OccurredAt - breakStart
|
||||
if breakElapsed >= minBreakThreshold {
|
||||
totalBreak += breakElapsed
|
||||
} else {
|
||||
totalWork += breakElapsed
|
||||
}
|
||||
state = StateWorking
|
||||
workStart = e.OccurredAt
|
||||
case e.EventType == "in" && state == StateWorking:
|
||||
case e.EventType == "out" && state == StateWorking:
|
||||
totalWork += e.OccurredAt - workStart
|
||||
state = StateOnBreak
|
||||
breakStart = e.OccurredAt
|
||||
case e.EventType == "out" && state == StateOnBreak:
|
||||
breakStart = e.OccurredAt
|
||||
case e.EventType == "out" && state == StateIdle:
|
||||
state = StateOnBreak
|
||||
breakStart = e.OccurredAt
|
||||
}
|
||||
}
|
||||
|
||||
if state == StateWorking && dayEnd > 0 {
|
||||
totalWork += dayEnd - workStart
|
||||
}
|
||||
if state == StateOnBreak && dayEnd > 0 {
|
||||
breakElapsed := dayEnd - breakStart
|
||||
if breakElapsed >= minBreakThreshold {
|
||||
totalBreak += breakElapsed
|
||||
} else {
|
||||
totalWork += breakElapsed
|
||||
}
|
||||
}
|
||||
|
||||
return DailyTotals{TotalSeconds: totalWork, BreakSeconds: totalBreak}
|
||||
}
|
||||
Reference in New Issue
Block a user