package bot import ( "database/sql" "errors" "fmt" "time" ) // clockIn records a clock-in event for today. // Returns the formatted time or an error if already clocked in today. func (h *Handler) clockIn(chatID int64) (string, error) { user, day, err := h.getUserToday(chatID) if err != nil { return "", err } last, err := h.DB.GetLastEvent(user.ID) if err != nil && err != sql.ErrNoRows { return "", err } if last != nil && last.EventType == "in" { loc := loadLocation(user.Timezone) now := time.Now().In(loc) lastTime := time.Unix(last.OccurredAt, 0).In(loc) if lastTime.Format("2006-01-02") == now.Format("2006-01-02") { return "", errors.New("already clocked in") } } loc := loadLocation(user.Timezone) now := time.Now().In(loc) wt := day.CurrentWorkTypeID if err := h.DB.CreateEvent(user.ID, day.ID, "in", &wt, now.Unix(), ""); err != nil { return "", err } return fmt.Sprintf("clocked in at %s", now.Format("15:04")), nil } // clockOut records a clock-out event for today. // Returns the formatted time or an error if not clocked in. func (h *Handler) clockOut(chatID int64) (string, error) { user, day, err := h.getUserToday(chatID) if err != nil { return "", err } last, err := h.DB.GetLastEvent(user.ID) if err != nil { return "", err } if last == nil { return "", errors.New("no clock-in found — start with /clockin first") } if last.EventType == "out" { return "", errors.New("already clocked out") } loc := loadLocation(user.Timezone) now := time.Now().In(loc) if err := h.DB.CreateEvent(user.ID, day.ID, "out", nil, now.Unix(), ""); err != nil { return "", err } return fmt.Sprintf("clocked out at %s", now.Format("15:04")), nil } // dayOff toggles today as a day off. func (h *Handler) dayOff(chatID int64) (string, error) { user, day, err := h.getUserToday(chatID) if err != nil { return "", err } if day.IsDayOff { if err := h.DB.RemoveDayOff(user.ID, day.Date); err != nil { return "", err } return "day off removed", nil } if err := h.DB.SetDayOff(user.ID, day.Date, ""); err != nil { return "", err } return "today marked as day off", nil } // report returns today's work summary via buildDailyReport. func (h *Handler) report(chatID int64) (string, error) { user, day, err := h.getUserToday(chatID) if err != nil { return "", err } events, err := h.DB.EventsForDayByDayID(day.ID) if err != nil { return "", err } return h.buildDailyReport(user, day, events), nil } // toggleReport enables or disables the automatic daily report. func (h *Handler) toggleReport(chatID int64) (string, error) { user, err := h.getOrCreateUser(chatID) if err != nil { return "", err } user.ReportEnabled = !user.ReportEnabled if err := h.DB.UpdateUser(user); err != nil { return "", err } if user.ReportEnabled { return "daily report enabled", nil } return "daily report disabled", nil }