package main import ( syncsvc "verstak/internal/core/sync" "verstak/internal/core/worklog" ) func (a *App) ListWorklog(nodeID string) ([]WorklogDTO, error) { list, err := a.worklog.ListByNode(nodeID) if err != nil { return nil, err } return toWorklogDTOs(list), nil } func (a *App) CreateWorklog(nodeID, summary string, minutes int) (*WorklogDTO, error) { return a.CreateWorklogFull(nodeID, summary, "", "", minutes, false, false) } func (a *App) CreateWorklogFull(nodeID, summary, details, date string, minutes int, approximate, billable bool) (*WorklogDTO, error) { if date == "" { entry, err := a.worklog.Add(nodeID, summary, details, minutes, approximate, billable) if err != nil { return nil, err } _ = a.sync.RecordOp(syncsvc.EntityWorklog, entry.ID, syncsvc.OpCreate, worklogPayload(entry)) return entryToDTO(entry), nil } entry, err := a.worklog.AddWithDate(nodeID, summary, details, date, minutes, approximate, billable) if err != nil { return nil, err } _ = a.sync.RecordOp(syncsvc.EntityWorklog, entry.ID, syncsvc.OpCreate, worklogPayload(entry)) return entryToDTO(entry), nil } // --- report bindings --- func (a *App) ListWorklogReport(dateFrom, dateTo, nodeID string, includeChildren bool, billableFilter, approxFilter string) ([]worklog.ReportRow, error) { f := buildWorklogFilter(dateFrom, dateTo, nodeID, includeChildren, billableFilter, approxFilter) rows, err := a.worklog.ListReport(f) if err != nil { return nil, err } a.worklog.BuildReportPaths(rows) return rows, nil } func (a *App) WorklogReportSummary(dateFrom, dateTo, nodeID string, includeChildren bool, billableFilter, approxFilter string) (*worklog.ReportSummary, error) { f := buildWorklogFilter(dateFrom, dateTo, nodeID, includeChildren, billableFilter, approxFilter) return a.worklog.Summary(f) } func (a *App) ExportWorklogCSV(dateFrom, dateTo, nodeID string, includeChildren bool, billableFilter, approxFilter string) (string, error) { f := buildWorklogFilter(dateFrom, dateTo, nodeID, includeChildren, billableFilter, approxFilter) return a.worklog.ExportCSV(f) } func (a *App) ExportWorklogMarkdown(dateFrom, dateTo, nodeID string, includeChildren bool, billableFilter, approxFilter string) (string, error) { f := buildWorklogFilter(dateFrom, dateTo, nodeID, includeChildren, billableFilter, approxFilter) return a.worklog.ExportMarkdown(f) } func boolPtr(s string) *bool { switch s { case "yes": v := true return &v case "no": v := false return &v default: return nil } } func buildWorklogFilter(dateFrom, dateTo, nodeID string, includeChildren bool, billableFilter, approxFilter string) worklog.ReportFilter { return worklog.ReportFilter{ DateFrom: dateFrom, DateTo: dateTo, NodeID: nodeID, IncludeChildren: includeChildren, Billable: boolPtr(billableFilter), Approximate: boolPtr(approxFilter), } } // --- helpers --- func toWorklogDTOs(list []worklog.Entry) []WorklogDTO { result := make([]WorklogDTO, len(list)) for i := range list { result[i] = *entryToDTO(&list[i]) } return result } func entryToDTO(e *worklog.Entry) *WorklogDTO { mins := 0 if e.Minutes != nil { mins = *e.Minutes } return &WorklogDTO{ ID: e.ID, NodeID: e.NodeID, Summary: e.Summary, Minutes: mins, Date: e.Date, Details: e.Details, Approximate: e.Approximate, Billable: e.Billable, CreatedAt: e.CreatedAt.Format("2006-01-02T15:04:05Z"), } }