refactor: clean up code from comments
This commit is contained in:
parent
4ceed6f301
commit
29bdd3a2a4
8 changed files with 150 additions and 252 deletions
147
export.go
147
export.go
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue