refactor: clean up code from comments

This commit is contained in:
Patryk Hegenberg 2025-04-02 14:21:33 +02:00
parent 4ceed6f301
commit 29bdd3a2a4
8 changed files with 150 additions and 252 deletions

147
export.go
View file

@ -11,28 +11,28 @@ import (
)
type DailySummary struct {
Date string // YYYY-MM-DD Format
Day string // Mon, Tue, etc.
WorkStart string // HH:MM:SS - Frühester Arbeitsbeginn
WorkEnd string // HH:MM:SS - Spätestes Arbeitsende
BreakDuration time.Duration // Summe aller Pausenzeiten an diesem Tag
WorkDuration time.Duration // Summe aller Arbeitszeiten an diesem Tag
Tag string // Spezielle Tags für den Tag (Urlaub, Krank, Feiertag, Uni, Free...)
Date string
Day string
WorkStart string
WorkEnd string
BreakDuration time.Duration
WorkDuration time.Duration
Tag string
}
type ExcelEntry struct {
Date string // YYYY-MM-DD
Day string // Mon, Tue, etc.
WorkStart string // HH:MM:SS
WorkEnd string // HH:MM:SS
BreakDuration string // HH:MM:SS (formatiert)
Tag string // Spezielle Tags
Date string
Day string
WorkStart string
WorkEnd string
BreakDuration string
Tag string
}
func aggregateEntriesToDailySummaries(entries []TimeEntry, yearStart, yearEnd time.Time) (map[string]*DailySummary, error) {
dailyMap := make(map[string]*DailySummary)
location := yearStart.Location() // Verwende die Zeitzone des Startdatums
now := time.Now().In(location) // Aktuelle Zeit für laufende Einträge
location := yearStart.Location()
now := time.Now().In(location)
currentDay := yearStart
log.Println(currentDay)
@ -46,13 +46,13 @@ func aggregateEntriesToDailySummaries(entries []TimeEntry, yearStart, yearEnd ti
dailyMap[dayStr] = &DailySummary{
Date: dayStr,
Day: weekday.String()[:3], // Mon, Tue, etc.
Tag: tag, // Initialisiere mit "free" für Wochenende, sonst leer
Day: weekday.String()[:3],
Tag: tag,
}
currentDay = currentDay.Add(24 * time.Hour) // Gehe zum nächsten Tag
currentDay = currentDay.Add(24 * time.Hour)
}
fullDayTags := make(map[string]string) // Map, um ganztägige Ereignisse zu speichern (Datum -> Tag)
fullDayTags := make(map[string]string)
for _, entry := range entries {
if entry.StartTime.IsZero() {
@ -60,11 +60,11 @@ func aggregateEntriesToDailySummaries(entries []TimeEntry, yearStart, yearEnd ti
continue
}
startTime := entry.StartTime.In(location) // Stelle sicher, dass Zeiten in der korrekten Zeitzone sind
startTime := entry.StartTime.In(location)
endTime := entry.EndTime.Time.In(location)
validEndTime := entry.EndTime.Valid
if !validEndTime {
endTime = now // Nimm aktuelle Zeit für laufende Einträge
endTime = now
}
if endTime.Before(yearStart) || startTime.After(yearEnd) {
@ -82,7 +82,6 @@ func aggregateEntriesToDailySummaries(entries []TimeEntry, yearStart, yearEnd ti
loopTimeForTag := startTime
for loopTimeForTag.Before(endTime) || loopTimeForTag.Equal(endTime) {
dayStr := loopTimeForTag.Format("2006-01-02")
// Nur Tage innerhalb des Jahres berücksichtigen
if _, exists := dailyMap[dayStr]; exists {
existingTag := fullDayTags[dayStr]
if shouldOverwriteTag(existingTag, lowerTag) {
@ -102,7 +101,7 @@ func aggregateEntriesToDailySummaries(entries []TimeEntry, yearStart, yearEnd ti
summary, exists := dailyMap[dayStr]
if !exists {
log.Printf("WARN: Day %s not found in initial map during entry processing (ID: %d)", dayStr, entry.ID)
loopTime = dayEnd // Gehe zum nächsten Tag
loopTime = dayEnd
continue
}
@ -113,16 +112,15 @@ func aggregateEntriesToDailySummaries(entries []TimeEntry, yearStart, yearEnd ti
}
segmentDuration := segmentEnd.Sub(segmentStart)
if segmentDuration <= 0 { // Überspringe leere Segmente
if segmentDuration <= 0 {
loopTime = dayEnd
continue
}
timeStr := segmentStart.Format("15:04:05")
// endTimeStr := segmentEnd.Format("15:04:05") // Ende des Segments
switch lowerTag {
case TagWork: // Konstante verwenden
case TagWork:
summary.WorkDuration += segmentDuration
if summary.WorkStart == "" || timeStr < summary.WorkStart {
summary.WorkStart = timeStr
@ -140,7 +138,7 @@ func aggregateEntriesToDailySummaries(entries []TimeEntry, yearStart, yearEnd ti
summary.Tag = TagWork
}
case TagBreak: // Konstante verwenden
case TagBreak:
summary.BreakDuration += segmentDuration
default:
log.Printf("INFO: Encountered unknown tag '%s' during interval processing for entry ID %d on %s. Counting duration as 'work'.", entry.Tag, entry.ID, dayStr)
@ -157,17 +155,16 @@ func aggregateEntriesToDailySummaries(entries []TimeEntry, yearStart, yearEnd ti
summary.WorkEnd = entryEndTimeOnThisDayStr
}
if summary.Tag == "" || summary.Tag == "free" {
summary.Tag = TagWork // Behandle unbekannt wie Arbeit für den Tag-Typ
summary.Tag = TagWork
}
}
loopTime = dayEnd // Gehe zum nächsten Tag
loopTime = dayEnd
}
}
for dayStr, specialTag := range fullDayTags {
if summary, exists := dailyMap[dayStr]; exists {
// Nur überschreiben, wenn der neue Tag höhere oder gleiche Prio hat
if shouldOverwriteTag(summary.Tag, specialTag) {
summary.Tag = specialTag
summary.WorkStart = ""
@ -194,9 +191,9 @@ func shouldOverwriteTag(existingTag, newTag string) bool {
"feiertag": 1,
"urlaub": 1,
"uni": 2,
"work": 3, // Arbeit hat niedrigere Priorität als spezielle Tage
"break": 99, // Pause sollte nie der Haupt-Tag sein
"free": 100, // Frei hat niedrigste Priorität
"work": 3,
"break": 99,
"free": 100,
}
prioExisting, okExisting := priority[strings.ToLower(existingTag)]
if !okExisting {
@ -217,7 +214,7 @@ func convertDailyToExcelEntries(dailySummaries map[string]*DailySummary) []Excel
for d := range dailySummaries {
dates = append(dates, d)
}
sort.Strings(dates) // Sortiere die Datums-Strings (YYYY-MM-DD)
sort.Strings(dates)
for _, dateStr := range dates {
summary := dailySummaries[dateStr]
@ -226,8 +223,8 @@ func convertDailyToExcelEntries(dailySummaries map[string]*DailySummary) []Excel
Day: summary.Day,
WorkStart: summary.WorkStart,
WorkEnd: summary.WorkEnd,
BreakDuration: formatDuration(summary.BreakDuration), // Formatierte Dauer
Tag: summary.Tag, // Übernehme den finalen Tag
BreakDuration: formatDuration(summary.BreakDuration),
Tag: summary.Tag,
}
excelEntries = append(excelEntries, entry)
}
@ -236,7 +233,7 @@ func convertDailyToExcelEntries(dailySummaries map[string]*DailySummary) []Excel
func formatDuration(d time.Duration) string {
if d < 0 {
d = -d // Arbeite mit positivem Wert für die Berechnung
d = -d
sign := "-"
d = d.Round(time.Second)
h := int64(d.Hours())
@ -254,25 +251,23 @@ func formatDuration(d time.Duration) string {
func getSollExcelTime(dayOfWeek string) any {
var sollString string
switch dayOfWeek {
case "Mon", "Tue", "Thu", "Fri": // Standard-Arbeitstage
case "Mon", "Tue", "Thu", "Fri":
sollString = "08:00"
case "Wed": // Kurzer Tag
case "Wed":
sollString = "04:00"
default: // Sa, So
return nil // Kein Soll an diesen Tagen
default:
return nil
}
sollDur, err := time.Parse("15:04", sollString)
if err != nil {
log.Printf("ERROR: Could not parse hardcoded soll string '%s': %v", sollString, err)
return nil // Fehler beim Parsen
return nil
}
return float64(sollDur.Hour())/24.0 + float64(sollDur.Minute())/(24.0*60.0)
}
func writeExcelSheet(entries []ExcelEntry, name string) error {
// Sortierung erfolgt jetzt in convertDailyToExcelEntries
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
@ -291,7 +286,7 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
if err != nil {
existingIndex, _ := f.GetSheetIndex(sheetName)
if existingIndex == -1 {
sheetName = "Sheet1" // Fallback auf Default
sheetName = "Sheet1"
index, _ = f.GetSheetIndex(sheetName)
if index == -1 {
return fmt.Errorf("could not create or find sheet '%s' or 'Sheet1': %w", sheetName, err)
@ -312,9 +307,9 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
f.SetCellValue(sheetName, "B3", "Datum")
f.SetCellValue(sheetName, "C3", "Tag")
f.SetCellValue(sheetName, "D3", "Status / Zeit") // Titel angepasst
f.SetCellValue(sheetName, "D3", "Status / Zeit")
f.MergeCell(sheetName, "D3", "E3")
f.SetCellValue(sheetName, "G3", "Dauer") // Titel angepasst
f.SetCellValue(sheetName, "G3", "Dauer")
f.MergeCell(sheetName, "G3", "H3")
f.SetCellValue(sheetName, "I3", "Pause")
f.SetCellValue(sheetName, "J3", "Netto")
@ -327,28 +322,26 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
f.SetCellValue(sheetName, "E4", "bis")
f.SetCellValue(sheetName, "G4", "brutto")
f.SetCellValue(sheetName, "H4", "")
f.SetCellValue(sheetName, "J4", "Ist (Netto)") // Titel angepasst
f.SetCellValue(sheetName, "J4", "Ist (Netto)")
f.SetCellValue(sheetName, "K4", "")
f.SetCellValue(sheetName, "L4", "Tag")
f.SetCellValue(sheetName, "N4", "Total")
f.SetCellValue(sheetName, "O4", "")
timeStyleCode := "hh:mm" // Format für Zeitpunkte und Dauer < 24h
timeStyleCode := "hh:mm"
timeStyle, _ := f.NewStyle(&excelize.Style{CustomNumFmt: &timeStyleCode})
dateStyleCode := "dd.mm.yyyy" // Format für Datum
dateStyleCode := "dd.mm.yyyy"
dateStyle, _ := f.NewStyle(&excelize.Style{CustomNumFmt: &dateStyleCode})
saldoStyleCode := "[h]:mm;[RED]-[h]:mm" // Verwende [h] um Stunden > 24 zu erlauben
saldoStyleCode := "[h]:mm;[RED]-[h]:mm"
saldoStyle, _ := f.NewStyle(&excelize.Style{CustomNumFmt: &saldoStyleCode})
headerStyle, _ := f.NewStyle(&excelize.Style{
Font: &excelize.Font{Bold: true},
Alignment: &excelize.Alignment{Horizontal: "center"},
})
centerStyle, _ := f.NewStyle(&excelize.Style{Alignment: &excelize.Alignment{Horizontal: "center"}})
// Stil für Zellen, die leer bleiben sollen (optional, um z.B. 0 auszublenden)
// emptyStyle, _ := f.NewStyle(&excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFFFFF"}, Pattern: 1}}) // Weißer Hintergrund
f.SetCellStyle(sheetName, "B3", "O4", headerStyle)
f.SetCellStyle(sheetName, "B1", "O1", headerStyle) // Titel auch
f.SetCellStyle(sheetName, "B1", "O1", headerStyle)
startRow := 6
for i, entry := range entries {
@ -361,7 +354,7 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
f.SetCellValue(sheetName, "B"+rowStr, dateValue)
f.SetCellStyle(sheetName, "B"+rowStr, "B"+rowStr, dateStyle)
} else {
f.SetCellValue(sheetName, "B"+rowStr, entry.Date) // Fallback
f.SetCellValue(sheetName, "B"+rowStr, entry.Date)
}
f.SetCellValue(sheetName, "C"+rowStr, entry.Day)
@ -370,11 +363,11 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
f.SetCellValue(sheetName, "K"+rowStr, sollExcelTime)
f.SetCellStyle(sheetName, "K"+rowStr, "K"+rowStr, timeStyle)
} else {
f.SetCellValue(sheetName, "K"+rowStr, "") // Leer für Wochenende etc.
f.SetCellValue(sheetName, "K"+rowStr, "")
}
switch tagLower {
case TagWork, "": // Normaler Arbeitstag oder nicht speziell getaggter Tag
case TagWork, "":
if entry.WorkStart != "" && entry.WorkEnd != "" {
startTime, _ := time.Parse("15:04:05", entry.WorkStart)
endTime, _ := time.Parse("15:04:05", entry.WorkEnd)
@ -402,7 +395,7 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
f.SetCellStyle(sheetName, "I"+rowStr, "I"+rowStr, timeStyle)
f.SetCellFormula(sheetName, "J"+rowStr, fmt.Sprintf("MAX(0, G%d-I%d)", row, row))
f.SetCellStyle(sheetName, "J"+rowStr, "J"+rowStr, saldoStyle) // Saldo-Style für Dauer
f.SetCellStyle(sheetName, "J"+rowStr, "J"+rowStr, saldoStyle)
} else {
f.SetCellValue(sheetName, "J"+rowStr, 0.0)
@ -417,13 +410,13 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
text = "Hochschule"
}
f.SetCellValue(sheetName, "D"+rowStr, text)
f.MergeCell(sheetName, "D"+rowStr, "I"+rowStr) // Verbinde D bis I
f.MergeCell(sheetName, "D"+rowStr, "I"+rowStr)
f.SetCellStyle(sheetName, "D"+rowStr, "I"+rowStr, centerStyle)
if sollExcelTime != nil {
f.SetCellValue(sheetName, "J"+rowStr, sollExcelTime)
} else {
f.SetCellValue(sheetName, "J"+rowStr, 0.0) // Kein Soll (WE), Netto 0
f.SetCellValue(sheetName, "J"+rowStr, 0.0)
}
f.SetCellStyle(sheetName, "J"+rowStr, "J"+rowStr, saldoStyle)
@ -435,19 +428,19 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
text = "Krank"
}
f.SetCellValue(sheetName, "D"+rowStr, text)
f.MergeCell(sheetName, "D"+rowStr, "I"+rowStr) // Verbinde D bis I
f.MergeCell(sheetName, "D"+rowStr, "I"+rowStr)
f.SetCellStyle(sheetName, "D"+rowStr, "I"+rowStr, centerStyle)
if sollExcelTime != nil {
f.SetCellValue(sheetName, "J"+rowStr, sollExcelTime)
} else {
f.SetCellValue(sheetName, "J"+rowStr, 0.0) // Kein Soll (WE), Netto 0
f.SetCellValue(sheetName, "J"+rowStr, 0.0)
}
f.SetCellStyle(sheetName, "J"+rowStr, "J"+rowStr, saldoStyle)
case "free": // Wochenende oder explizit "free"
case "free":
f.SetCellValue(sheetName, "D"+rowStr, "")
f.MergeCell(sheetName, "D"+rowStr, "I"+rowStr) // Verbinde D bis I
f.MergeCell(sheetName, "D"+rowStr, "I"+rowStr)
f.SetCellStyle(sheetName, "D"+rowStr, "I"+rowStr, centerStyle)
// J: Netto ist 0
f.SetCellValue(sheetName, "J"+rowStr, 0.0)
@ -459,27 +452,27 @@ func writeExcelSheet(entries []ExcelEntry, name string) error {
}
f.SetCellFormula(sheetName, "L"+rowStr, fmt.Sprintf("J%d-K%d", row, row))
f.SetCellStyle(sheetName, "L"+rowStr, "M"+rowStr, saldoStyle) // Style auf L und M
f.SetCellStyle(sheetName, "L"+rowStr, "M"+rowStr, saldoStyle)
if i == 0 { // Erste Datenzeile
if i == 0 {
f.SetCellFormula(sheetName, "N"+rowStr, fmt.Sprintf("L%d", row))
} else {
prevSaldoTotalCell := fmt.Sprintf("N%d", row-1)
f.SetCellFormula(sheetName, "N"+rowStr, fmt.Sprintf("%s+L%d", prevSaldoTotalCell, row))
}
f.SetCellStyle(sheetName, "N"+rowStr, "O"+rowStr, saldoStyle) // Style auf N und O
f.SetCellStyle(sheetName, "N"+rowStr, "O"+rowStr, saldoStyle)
}
f.SetColWidth(sheetName, "B", "B", 12) // Datum
f.SetColWidth(sheetName, "C", "C", 5) // Tag
f.SetColWidth(sheetName, "D", "E", 10) // Status/Zeit von/bis
f.SetColWidth(sheetName, "F", "F", 2) // Leer
f.SetColWidth(sheetName, "G", "H", 9) // Dauer brutto
f.SetColWidth(sheetName, "I", "I", 9) // Pause
f.SetColWidth(sheetName, "J", "J", 9) // Netto
f.SetColWidth(sheetName, "K", "K", 9) // Soll
f.SetColWidth(sheetName, "L", "M", 9) // Saldo Tag
f.SetColWidth(sheetName, "N", "O", 10) // Saldo Total
f.SetColWidth(sheetName, "B", "B", 12)
f.SetColWidth(sheetName, "C", "C", 5)
f.SetColWidth(sheetName, "D", "E", 10)
f.SetColWidth(sheetName, "F", "F", 2)
f.SetColWidth(sheetName, "G", "H", 9)
f.SetColWidth(sheetName, "I", "I", 9)
f.SetColWidth(sheetName, "J", "J", 9)
f.SetColWidth(sheetName, "K", "K", 9)
f.SetColWidth(sheetName, "L", "M", 9)
f.SetColWidth(sheetName, "N", "O", 10)
f.SetActiveSheet(index)
if err := f.SaveAs(name); err != nil {