Documentation
¶
Overview ¶
Package clock is Timeclock's payroll logic and storage: pay periods, time entries, time off, timesheets, approvals, exceptions and reports.
Index ¶
- Constants
- Variables
- func Hours(d time.Duration) float64
- func HoursByDay(spans []Span, loc *time.Location, rule OvertimeRule) map[Date]DayHours
- func Revoked(err error) bool
- type Absence
- type Activity
- type Actor
- type AuditEntry
- type AuditPerson
- type AuditQuery
- type CalendarFeedStatus
- type Customer
- type Date
- func (d Date) AddDays(n int) Date
- func (d Date) After(o Date) bool
- func (d Date) Before(o Date) bool
- func (d Date) DaysSince(o Date) int
- func (d Date) In(loc *time.Location) time.Time
- func (d Date) IsZero() bool
- func (d Date) MarshalText() ([]byte, error)
- func (d Date) String() string
- func (d Date) Time() time.Time
- func (d *Date) UnmarshalText(b []byte) error
- func (d Date) Weekday() time.Weekday
- type DayHours
- type DayProjectHours
- type DaySummary
- type Entry
- type EntryInput
- type Exception
- type FeedContents
- type FeedOwner
- type GoogleCalendarStatus
- type GoogleCalendars
- func (g *GoogleCalendars) AuthURL(s *Service, actor Actor, returnPath string) (string, error)
- func (g *GoogleCalendars) Complete(ctx context.Context, s *Service, actor Actor, code, state string) error
- func (g *GoogleCalendars) Disconnect(ctx context.Context, s *Service, actor Actor) error
- func (g *GoogleCalendars) Drop(s *Service, actor Actor)
- func (g *GoogleCalendars) Forget(ctx context.Context, s *Service, actor Actor) error
- func (g *GoogleCalendars) Return(s *Service, actor Actor, state string) (string, error)
- func (g *GoogleCalendars) Status(ctx context.Context, s *Service, actor Actor) (GoogleCalendarStatus, error)
- func (g *GoogleCalendars) TokenSource(ctx context.Context, s *Service, actor Actor) (oauth2.TokenSource, bool, error)
- type GoogleClient
- type Holiday
- type HolidayDay
- type HolidayDayInput
- type HolidayInput
- type MeetingChoice
- type OvertimeRule
- type PayCycle
- type Period
- type PeriodSummary
- type Person
- type PersonUpdate
- type Project
- type ProjectHours
- type ProjectInput
- type RecentWork
- type Reminder
- type Reminders
- type Scheme
- type Service
- func (s *Service) Absences(ctx context.Context, from, to Date) ([]Absence, error)
- func (s *Service) Activity(ctx context.Context, actor Actor) ([]Activity, error)
- func (s *Service) Audit(ctx context.Context, actor Actor, q AuditQuery) ([]AuditEntry, bool, error)
- func (s *Service) AuditPeople(ctx context.Context, actor Actor) ([]AuditPerson, error)
- func (s *Service) CalendarFeed(ctx context.Context, actor Actor) (CalendarFeedStatus, error)
- func (s *Service) CalendarFeedOwner(ctx context.Context, token string) (FeedOwner, error)
- func (s *Service) CancelTimeOff(ctx context.Context, actor Actor, id uuid.UUID) error
- func (s *Service) ClockIn(ctx context.Context, actor Actor, projectID *uuid.UUID, note string) (Entry, error)
- func (s *Service) ClockOut(ctx context.Context, actor Actor) (Entry, error)
- func (s *Service) CreateEntry(ctx context.Context, actor Actor, in EntryInput) (Entry, error)
- func (s *Service) Customers(ctx context.Context, archived bool) ([]Customer, error)
- func (s *Service) Decide(ctx context.Context, actor Actor, id uuid.UUID, approve bool, note string) (Timesheet, error)
- func (s *Service) DecideTimeOff(ctx context.Context, actor Actor, id uuid.UUID, approve bool, note string) (TimeOff, error)
- func (s *Service) DeleteCustomer(ctx context.Context, actor Actor, id uuid.UUID) error
- func (s *Service) DeleteEntry(ctx context.Context, actor Actor, id uuid.UUID) error
- func (s *Service) DeleteHoliday(ctx context.Context, actor Actor, id uuid.UUID) error
- func (s *Service) DeleteProject(ctx context.Context, actor Actor, id uuid.UUID) error
- func (s *Service) DueReminders(ctx context.Context) ([]Reminder, error)
- func (s *Service) EnsureWorkspace(ctx context.Context, key string) (Workspace, error)
- func (s *Service) Entries(ctx context.Context, actor Actor, personID string, from, to Date) ([]Entry, error)
- func (s *Service) Exceptions(ctx context.Context, actor Actor, day Date) ([]Exception, error)
- func (s *Service) Holidays(ctx context.Context) ([]Holiday, error)
- func (s *Service) HoursByDayAndProject(ctx context.Context, actor Actor, from, to Date, mine bool) ([]DayProjectHours, error)
- func (s *Service) In(workspace uuid.UUID) *Service
- func (s *Service) Meetings(ctx context.Context, actor Actor, meetings []string) (map[string]MeetingChoice, error)
- func (s *Service) NewCalendarFeed(ctx context.Context, actor Actor, c FeedContents) (string, CalendarFeedStatus, error)
- func (s *Service) Payroll(ctx context.Context, actor Actor, day Date) ([]PeriodSummary, error)
- func (s *Service) PendingTimeOff(ctx context.Context, actor Actor) ([]TimeOff, error)
- func (s *Service) People(ctx context.Context, actor Actor) ([]Person, error)
- func (s *Service) ProjectReport(ctx context.Context, actor Actor, from, to Date) ([]ProjectHours, error)
- func (s *Service) Projects(ctx context.Context, archived bool) ([]Project, error)
- func (s *Service) RecentWork(ctx context.Context, actor Actor, limit int) ([]RecentWork, error)
- func (s *Service) RememberMeeting(ctx context.Context, actor Actor, meeting string, projectID *uuid.UUID) error
- func (s *Service) Reopen(ctx context.Context, actor Actor, id uuid.UUID, note string) (Timesheet, error)
- func (s *Service) RequestTimeOff(ctx context.Context, actor Actor, in TimeOffInput) ([]TimeOff, error)
- func (s *Service) Running(ctx context.Context, actor Actor) (*Entry, error)
- func (s *Service) SaveCustomer(ctx context.Context, actor Actor, id uuid.UUID, name string, archived bool) (Customer, error)
- func (s *Service) SaveHoliday(ctx context.Context, actor Actor, id uuid.UUID, in HolidayInput) (Holiday, error)
- func (s *Service) SaveProject(ctx context.Context, actor Actor, id uuid.UUID, in ProjectInput) (Project, error)
- func (s *Service) SetAdmin(ctx context.Context, actor Actor, id string, admin bool) (Person, error)
- func (s *Service) SetCalendarFeed(ctx context.Context, actor Actor, c FeedContents) (CalendarFeedStatus, error)
- func (s *Service) SetOwnTimezone(ctx context.Context, actor Actor, tz string) (Person, error)
- func (s *Service) SetTheme(ctx context.Context, actor Actor, t Theme) (Theme, error)
- func (s *Service) Settings(ctx context.Context) (Settings, error)
- func (s *Service) StopCalendarFeed(ctx context.Context, actor Actor) error
- func (s *Service) Submit(ctx context.Context, actor Actor, personID string, day Date) (PeriodSummary, error)
- func (s *Service) Summary(ctx context.Context, actor Actor, personID string, day Date) (PeriodSummary, error)
- func (s *Service) Switch(ctx context.Context, actor Actor, projectID *uuid.UUID, note string) (Entry, error)
- func (s *Service) Sync(ctx context.Context, hp host.Person) (Actor, error)
- func (s *Service) SyncAll(ctx context.Context, people []host.Person) error
- func (s *Service) Team(ctx context.Context, actor Actor, day Date) ([]PeriodSummary, error)
- func (s *Service) Theme(ctx context.Context) (Theme, error)
- func (s *Service) TimeOff(ctx context.Context, actor Actor, personID string, from, to Date) ([]TimeOff, error)
- func (s *Service) Today(cfg Settings) Date
- func (s *Service) TodayFor(cfg Settings, p Person) Date
- func (s *Service) UpdateEntry(ctx context.Context, actor Actor, id uuid.UUID, in EntryInput) (Entry, error)
- func (s *Service) UpdatePerson(ctx context.Context, actor Actor, id string, in PersonUpdate) (Person, error)
- func (s *Service) UpdateSettings(ctx context.Context, actor Actor, in Settings) (Settings, error)
- func (s *Service) Workspace() uuid.UUID
- func (s *Service) Workspaces(ctx context.Context) ([]Workspace, error)
- type Settings
- type Span
- type Theme
- type ThemeSeed
- type TimeOff
- type TimeOffInput
- type Timesheet
- type Toggl
- func (t *Toggl) Configure(ctx context.Context, s *Service, actor Actor, in TogglSetup) error
- func (t *Toggl) Disconnect(ctx context.Context, s *Service, actor Actor) error
- func (t *Toggl) Preview(ctx context.Context, s *Service, actor Actor, token string, workspace int64) (TogglPreview, error)
- func (t *Toggl) Register(workers *hopper.Workers) hopper.PeriodicJob
- func (t *Toggl) RequestSync(ctx context.Context, s *Service, actor Actor) error
- func (t *Toggl) Resolve(ctx context.Context, s *Service, actor Actor, id uuid.UUID, in TogglResolution) error
- func (t *Toggl) Status(ctx context.Context, s *Service, actor Actor) (TogglStatus, error)
- type TogglIssue
- type TogglMapping
- type TogglPreview
- type TogglProject
- type TogglResolution
- type TogglRoles
- type TogglSetup
- type TogglStatus
- type TogglTimeOff
- type Workspace
Constants ¶
const ( Vacation = "vacation" Sick = "sick" )
The kinds of time off.
const ( StatusPending = "pending" StatusSubmitted = "submitted" StatusApproved = "approved" StatusRejected = "rejected" )
The states of time off and timesheets.
const ( ExceptionClockRunning = "clock_running" // a clock has run past the long-entry limit ExceptionLongEntry = "long_entry" // an entry is longer than the limit ExceptionNotSubmitted = "not_submitted" // the period ended without a timesheet ExceptionAwaitingApproval = "awaiting_approval" // a timesheet for an ended period is undecided ExceptionRejected = "rejected" // a timesheet was sent back and not resubmitted ExceptionTimeOffPending = "time_off_pending" // time off in the period is undecided ExceptionNoTime = "no_time" // the period ended with nothing recorded )
The kinds of exception.
const ( ReminderClockRunning = "clock_running" ReminderTimesheetDue = "timesheet_due" )
The kinds of reminder.
const DefaultWorkspace = "default"
DefaultWorkspace is the key of the workspace a deployment has without asking for any: a host that has one organization, or a server on its own.
const GoogleRevokeURL = "https://oauth2.googleapis.com/revoke"
GoogleRevokeURL is where Google takes back a token.
const HolidayHours = 8.0
HolidayHours is what a holiday day pays when the admin doesn't say.
Variables ¶
var ( ErrClockRunning = Problems.Define(problem.Type{ Code: "clock_running", Status: http.StatusConflict, Title: "Clock already running", Doc: "The person is already clocked in. Clock out before clocking in again.", }) ErrClockNotRunning = Problems.Define(problem.Type{ Code: "clock_not_running", Status: http.StatusConflict, Title: "Clock not running", Doc: "The person isn't clocked in, so there is nothing to stop.", }) ErrOverlap = Problems.Define(problem.Type{ Code: "entry_overlaps", Status: http.StatusConflict, Title: "Time off already recorded", Doc: "The person already has time off of this kind on one of these days.", }) ErrHolidayTaken = Problems.Define(problem.Type{ Code: "holiday_day_taken", Status: http.StatusConflict, Title: "Day already a holiday", Doc: "Another holiday already covers one of these days. A day is one holiday, so it is never paid twice.", }) ErrLocked = Problems.Define(problem.Type{ Code: "period_locked", Status: http.StatusConflict, Title: "Timesheet already submitted", Doc: "The day is in a timesheet that was submitted or approved, so its time can't change. A manager or admin can send the timesheet back.", }) ErrDescriptionRequired = Problems.Define(problem.Type{ Code: "description_required", Status: http.StatusUnprocessableEntity, Title: "Description required", Doc: "This workspace requires a nonblank description on every time entry.", }) ErrProjectRequired = Problems.Define(problem.Type{ Code: "project_required", Status: http.StatusUnprocessableEntity, Title: "Project required", Doc: "This organization requires every time entry to name a project.", }) ErrProjectArchived = Problems.Define(problem.Type{ Code: "project_archived", Status: http.StatusConflict, Title: "Project archived", Doc: "The project is archived, so no new time can be recorded on it.", }) ErrFuture = Problems.Define(problem.Type{ Code: "in_the_future", Status: http.StatusUnprocessableEntity, Title: "Time in the future", Doc: "Worked time can't end in the future, unless the organization allows planned time, and then no more than a year ahead. A running clock can't start in the future.", }) ErrPlannedTime = Problems.Define(problem.Type{ Code: "planned_time_in_period", Status: http.StatusConflict, Title: "Time still planned", Doc: "A timesheet can't be submitted while its pay period has time that hasn't happened yet. Submit it once that time has passed, or remove it.", }) ErrPeriodOpen = Problems.Define(problem.Type{ Code: "clock_still_running", Status: http.StatusConflict, Title: "Clock still running", Doc: "A timesheet can't be submitted while the person is clocked in during its pay period. Clock out first.", }) ErrDoesNotSubmit = Problems.Define(problem.Type{ Code: "does_not_submit_timesheets", Status: http.StatusConflict, Title: "Doesn't submit timesheets", Doc: "This person's time is for reports only: they don't submit timesheets, and aren't in payroll. An admin can change that in Settings.", }) ErrAlreadySubmitted = Problems.Define(problem.Type{ Code: "already_submitted", Status: http.StatusConflict, Title: "Timesheet already submitted", Doc: "The timesheet for this pay period was already submitted.", }) ErrNotSubmitted = Problems.Define(problem.Type{ Code: "not_awaiting_decision", Status: http.StatusConflict, Title: "Nothing to decide", Doc: "It isn't waiting for a decision: it was never submitted, or someone already decided it.", }) ErrOwnApproval = Problems.Define(problem.Type{ Code: "own_approval", Status: http.StatusForbidden, Title: "Can't approve your own time", Doc: "A manager can't approve their own timesheet or time off. Their manager or an admin does.", }) ErrInUse = Problems.Define(problem.Type{ Code: "in_use", Status: http.StatusConflict, Title: "Still in use", Doc: "A customer with projects, or a project with time recorded on it, can't be deleted. Archive it instead.", }) ErrNameTaken = Problems.Define(problem.Type{ Code: "name_taken", Status: http.StatusConflict, Title: "Name already used", Doc: "Another one already has this name.", }) ErrManagerLoop = Problems.Define(problem.Type{ Code: "manager_loop", Status: http.StatusUnprocessableEntity, Title: "Manager chain loops", Doc: "A person can't be their own manager, directly or through the people they manage.", }) )
The failures a status alone doesn't describe.
var ( ErrInvalidCredentials = Problems.Define(problem.Type{ Code: "invalid_credentials", Status: http.StatusUnauthorized, Title: "Wrong email or password", Doc: "The email and password don't match an account. The answer is the same whether or not the email is known.", }) ErrTooManyAttempts = Problems.Define(problem.Type{ Code: "too_many_attempts", Status: http.StatusTooManyRequests, Title: "Too many attempts", Doc: "Sign-in for this account or from this address is paused after repeated failures. Retry-After says for how long.", }) ErrWeakPassword = Problems.Define(problem.Type{ Code: "weak_password", Status: http.StatusUnprocessableEntity, Title: "Password too short", Doc: "A password is at least 10 characters and at most 128. There are no other rules about what it contains.", }) ErrBreachedPassword = Problems.Define(problem.Type{ Code: "breached_password", Status: http.StatusUnprocessableEntity, Title: "Password is known from a breach", Doc: "The password appears in a public list of passwords from data breaches, so it is easy to guess.", }) ErrLinkExpired = Problems.Define(problem.Type{ Code: "link_expired", Status: http.StatusGone, Title: "Link no longer works", Doc: "An invitation or password-reset link was already used, was withdrawn, or is too old.", }) ErrInvalidCode = Problems.Define(problem.Type{ Code: "invalid_code", Status: http.StatusUnauthorized, Title: "Wrong code", Doc: "The authenticator or recovery code isn't right, or was already used.", }) ErrPasskeyRefused = Problems.Define(problem.Type{ Code: "passkey_refused", Status: http.StatusUnauthorized, Title: "Passkey not accepted", Doc: "The passkey isn't one this server knows, or its answer didn't verify.", }) ErrSSORequired = Problems.Define(problem.Type{ Code: "sso_required", Status: http.StatusForbidden, Title: "Single sign-on required", Doc: "The workspace can only be entered by signing in through its identity provider.", }) ErrNotAMember = Problems.Define(problem.Type{ Code: "not_a_member", Status: http.StatusForbidden, Title: "Not in this workspace", Doc: "The account doesn't belong to the workspace it asked for.", }) )
What a standalone server's sign-in refuses.
var DefaultFeedContents = FeedContents{Holidays: true, TimeOff: true}
DefaultFeedContents is what a feed lists until its owner says otherwise.
var ErrGoogleState = problem.Status(http.StatusBadRequest, "this Google Calendar connection was started elsewhere or has expired; start it again")
ErrGoogleState is a consent that came back to someone it wasn't for, or too late.
var GoogleEndpoint = oauth2.Endpoint{ AuthURL: "https://accounts.google.com/o/oauth2/v2/auth", TokenURL: "https://oauth2.googleapis.com/token", AuthStyle: oauth2.AuthStyleInParams, }
GoogleEndpoint is Google's OAuth endpoint.
var Problems = problem.NewRegistry("timeclock")
Problems are Timeclock's problem types, documented at /problems/. Codes are API contract, keyed in the web app's catalog under apiErrors: never rename one.
Functions ¶
func HoursByDay ¶
HoursByDay adds up spans per calendar day in loc, counting overlapping spans once. Within each workweek, time beyond the weekly threshold is overtime, counted on the day it was worked, so a week that straddles two pay periods puts its overtime in the period the extra hours fell in. spans must include the whole of every workweek the caller reports on.
Types ¶
type Activity ¶ added in v0.2.0
type Activity struct {
Person Person `json:"person"`
Running *Entry `json:"running,omitempty" doc:"Their running clock."`
Today float64 `json:"today" doc:"Hours today, with the running clock up to now."`
Week float64 `json:"week" doc:"Hours this workweek, with the running clock up to now."`
}
Activity is what one person is doing now and how much they have tracked.
type Actor ¶
type Actor struct {
Person
// Admin runs payroll.
Admin bool
// Auditor reads the audit log, as the host says; apart from Admin.
Auditor bool
}
Actor is the person making a request.
type AuditEntry ¶
type AuditEntry struct {
ID uuid.UUID `json:"id"`
At time.Time `json:"at"`
Actor string `json:"actor"`
Action string `json:"action"`
PersonID string `json:"personId,omitempty"`
Detail map[string]any `json:"detail"`
}
AuditEntry is one change to payroll data.
type AuditPerson ¶ added in v0.27.0
type AuditPerson struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
AvatarURL string `json:"avatarUrl"`
}
AuditPerson is who someone the audit log mentions is: no more than that.
type AuditQuery ¶ added in v0.27.0
type AuditQuery struct {
// PersonID keeps only changes to this person's time; empty keeps everything.
PersonID string
// Before is the last entry of the page before: this page goes on from it.
Before *uuid.UUID
// Until starts the log at the end of this day, in the organization's time zone.
Until *Date
Limit int
}
AuditQuery picks a page of the audit log, newest first.
type CalendarFeedStatus ¶ added in v0.25.0
type CalendarFeedStatus struct {
FeedContents
Enabled bool `json:"enabled" doc:"Whether the caller has a calendar feed."`
CreatedAt *time.Time `json:"createdAt,omitempty" doc:"When its address was made."`
}
CalendarFeedStatus is whether a person has a calendar feed, and what it lists. Its address is shown only when it is made.
type Customer ¶
type Customer struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Archived bool `json:"archived"`
}
Customer is who work is done for.
type Date ¶
type Date struct {
// contains filtered or unexported fields
}
Date is a calendar day, with no time or zone, written YYYY-MM-DD.
func DateFromTime ¶
DateFromTime is the calendar day of a time read from a DATE column.
func (Date) MarshalText ¶
MarshalText writes YYYY-MM-DD.
func (*Date) UnmarshalText ¶
UnmarshalText reads YYYY-MM-DD.
type DayProjectHours ¶ added in v0.2.0
type DayProjectHours struct {
Day Date `json:"day" format:"date"`
ProjectID string `json:"projectId" doc:"Empty for time with no project."`
Hours float64 `json:"hours"`
}
DayProjectHours is time on one project on one day, with a running clock counted up to now.
type DaySummary ¶
type DaySummary struct {
Day Date `json:"day" format:"date"`
Regular float64 `json:"regular"`
Overtime float64 `json:"overtime"`
Vacation float64 `json:"vacation"`
Sick float64 `json:"sick"`
Holiday float64 `json:"holiday" doc:"Paid company holiday hours: not time worked, so never overtime."`
// HolidayName names the company holiday on the day, paid or not.
HolidayName string `json:"holidayName,omitempty" doc:"The company holiday on this day."`
}
DaySummary is one day of a person's pay period, in hours.
type Entry ¶
type Entry struct {
ID uuid.UUID `json:"id"`
PersonID string `json:"personId"`
ProjectID *uuid.UUID `json:"projectId,omitempty"`
StartedAt time.Time `json:"startedAt"`
EndedAt *time.Time `json:"endedAt,omitempty" doc:"Absent while the clock is running."`
Note string `json:"note"`
Source string `json:"source" enum:"clock,manual,toggl"`
Locked bool `json:"locked" doc:"In a submitted or approved timesheet, so it can't change."`
}
Entry is a stretch of work.
type EntryInput ¶
type EntryInput struct {
PersonID string `` /* 126-byte string literal not displayed */
ProjectID *uuid.UUID `json:"projectId,omitempty"`
StartedAt time.Time `json:"startedAt"`
EndedAt *time.Time `json:"endedAt,omitempty" doc:"Absent leaves a running clock running."`
Note string `json:"note,omitempty" maxLength:"2000"`
}
EntryInput is a time entry as written by hand.
type Exception ¶
type Exception struct {
Kind string `json:"kind" enum:"clock_running,long_entry,not_submitted,awaiting_approval,rejected,time_off_pending,no_time"`
PersonID string `json:"personId"`
PersonName string `json:"personName"`
Day *Date `json:"day,omitempty" format:"date"`
EntryID *uuid.UUID `json:"entryId,omitempty"`
Hours float64 `json:"hours,omitempty" doc:"The hours the exception is about: the entry's length, the overtime, or the pending time off."`
}
Exception is something in a pay period that payroll should look at before paying from it.
type FeedContents ¶ added in v0.25.0
type FeedContents struct {
Holidays bool `json:"holidays" doc:"The company's holidays."`
TimeOff bool `json:"timeOff" doc:"Who is out: everyone's approved time off."`
TrackedTime bool `json:"trackedTime" doc:"The subscriber's own tracked and planned time."`
}
FeedContents is what a calendar feed lists. At least one is on.
type FeedOwner ¶ added in v0.25.0
type FeedOwner struct {
Workspace Workspace
PersonID string
Contents FeedContents
}
FeedOwner is whose a calendar feed is, the workspace it lists, and what.
type GoogleCalendarStatus ¶ added in v0.21.0
type GoogleCalendarStatus struct {
Connected bool `json:"connected"`
Account string `json:"account,omitempty" doc:"The Google account it reads, normally an email address."`
ConnectedAt *time.Time `json:"connectedAt,omitempty"`
}
GoogleCalendarStatus is whether a person has connected their calendar.
type GoogleCalendars ¶ added in v0.21.0
type GoogleCalendars struct {
// contains filtered or unexported fields
}
GoogleCalendars are the calendars people connect themselves. Timeclock sends a person to Google's consent screen, keeps the refresh token Google gives back, sealed with the integration key, and reads their events with it until they disconnect or revoke it.
func NewGoogleCalendars ¶ added in v0.21.0
func NewGoogleCalendars(key string, c *GoogleClient, logger *slog.Logger) (*GoogleCalendars, error)
NewGoogleCalendars returns nil when there is no client: nobody can connect.
func (*GoogleCalendars) AuthURL ¶ added in v0.21.0
AuthURL is Google's consent screen for the actor to connect their calendar, coming back to returnPath afterwards.
func (*GoogleCalendars) Complete ¶ added in v0.21.0
func (g *GoogleCalendars) Complete(ctx context.Context, s *Service, actor Actor, code, state string) error
Complete exchanges the code Google returned for the actor's tokens and keeps the refresh token.
func (*GoogleCalendars) Disconnect ¶ added in v0.21.0
Disconnect drops the actor's connection and asks Google to revoke its token. A revocation that fails still disconnects: Timeclock no longer has the token either way.
func (*GoogleCalendars) Drop ¶ added in v0.21.0
func (g *GoogleCalendars) Drop(s *Service, actor Actor)
Drop forgets the actor's access token, so the next read refreshes it.
func (*GoogleCalendars) Forget ¶ added in v0.21.0
Forget drops the actor's connection without asking Google, which has already let it go.
func (*GoogleCalendars) Return ¶ added in v0.21.0
Return reads where a consent started from, for whoever it was for: the path to go back to.
func (*GoogleCalendars) Status ¶ added in v0.21.0
func (g *GoogleCalendars) Status(ctx context.Context, s *Service, actor Actor) (GoogleCalendarStatus, error)
Status is whether the actor has connected their calendar.
func (*GoogleCalendars) TokenSource ¶ added in v0.21.0
func (g *GoogleCalendars) TokenSource(ctx context.Context, s *Service, actor Actor) (oauth2.TokenSource, bool, error)
TokenSource is the actor's own connection, or ok false when they have none.
type GoogleClient ¶ added in v0.21.0
type GoogleClient struct {
ClientID, ClientSecret, RedirectURL string
Endpoint oauth2.Endpoint
RevokeURL string
}
GoogleClient is the OAuth client people connect their calendars through.
type Holiday ¶ added in v0.15.0
type Holiday struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Days []HolidayDay `json:"days"`
}
Holiday is a company holiday: a name and the observed days it covers, each with the hours it pays.
type HolidayDay ¶ added in v0.15.0
type HolidayDay struct {
Day Date `json:"day" format:"date"`
Hours float64 `json:"hours" doc:"Paid hours on the day."`
}
HolidayDay is one observed day of a holiday.
type HolidayDayInput ¶ added in v0.15.0
type HolidayDayInput struct {
Day Date `json:"day" format:"date"`
Hours float64 `json:"hours,omitempty" minimum:"0" maximum:"24" doc:"Paid hours on the day. Absent or 0 pays 8."`
}
HolidayDayInput is one observed day and what it pays.
type HolidayInput ¶ added in v0.15.0
type HolidayInput struct {
Name string `json:"name" minLength:"1" maxLength:"120"`
Days []HolidayDayInput `json:"days" minItems:"1" maxItems:"31" doc:"The observed days. A holiday can cover several days, not necessarily in a row."`
}
HolidayInput is a holiday as an admin enters it: the days the company observes, so a holiday on a Saturday is entered on the Friday off.
type MeetingChoice ¶ added in v0.22.0
MeetingChoice is the project a person copies a meeting to: nil for none.
type OvertimeRule ¶
type OvertimeRule struct {
// WeekStart is the day the workweek starts.
WeekStart time.Weekday
// Weekly is the time in one workweek beyond which work is overtime. Zero
// means no overtime.
Weekly time.Duration
}
OvertimeRule is how overtime is counted.
type Period ¶
Period is a pay period: both days are in it.
func PeriodAfter ¶
PeriodAfter returns the pay period that starts the day after p ends.
func PeriodBefore ¶
PeriodBefore returns the pay period that ends the day before p starts.
func PeriodContaining ¶
PeriodContaining returns the pay period d falls in. anchor is the first day of some weekly or biweekly period; the other cycles follow the calendar.
type PeriodSummary ¶
type PeriodSummary struct {
Person Person `json:"person"`
Period Period `json:"period"`
Days []DaySummary `json:"days"`
Regular float64 `json:"regular"`
Overtime float64 `json:"overtime"`
Vacation float64 `json:"vacation" doc:"Approved vacation hours."`
Sick float64 `json:"sick" doc:"Approved sick hours."`
Holiday float64 `json:"holiday" doc:"Paid company holiday hours."`
// PendingTimeOff is hours of time off still waiting for a decision,
// which are not in Vacation or Sick.
PendingTimeOff float64 `json:"pendingTimeOff"`
Running bool `json:"running" doc:"A clock is running; its time isn't counted until it stops."`
Timesheet *Timesheet `json:"timesheet,omitempty" doc:"Absent until the person submits."`
}
PeriodSummary is a person's pay period: what payroll pays from.
type Person ¶
type Person struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
AvatarURL string `json:"avatarUrl"`
Timezone string `` /* 138-byte string literal not displayed */
ManagerID string `json:"managerId" doc:"Who approves this person's time; empty when no one is assigned."`
ManagerOverrideID string `json:"managerOverrideId" doc:"The local manager override; empty follows the directory."`
DirectoryManagerID string `json:"directoryManagerId" doc:"The manager supplied by the host directory, used when no local override is set."`
OvertimeExempt bool `json:"overtimeExempt"`
PayrollID string `json:"payrollId" doc:"The person's id in the payroll system, for the export."`
Active bool `json:"active"`
// SubmitsTimesheets is what applies: their own choice, or else the workspace's.
SubmitsTimesheets bool `json:"submitsTimesheets" doc:"They submit timesheets and are in payroll. Without, their time is for reports only."`
// Admin runs payroll and manages Timeclock: the host says so (HostAdmin),
// or an admin granted it here.
Admin bool `json:"admin" doc:"Runs payroll and manages Timeclock."`
HostAdmin bool `json:"hostAdmin" doc:"The host application makes them an admin; only the host can take that away."`
// SubmitsTimesheetsOverride is their own choice; nil follows the workspace.
SubmitsTimesheetsOverride *bool `json:"submitsTimesheetsOverride" nullable:"true" doc:"Set for this person; null follows the workspace's setting."`
// HolidayPay is what applies: their own choice, or else the workspace's.
HolidayPay bool `json:"holidayPay" doc:"They are paid for company holidays."`
// HolidayPayOverride is their own choice; nil follows the workspace.
HolidayPayOverride *bool `json:"holidayPayOverride" nullable:"true" doc:"Set for this person; null follows the workspace's holiday pay."`
}
Person is someone who tracks time.
type PersonUpdate ¶
type PersonUpdate struct {
Timezone string `json:"timezone" doc:"The IANA time zone their days are cut in. Empty uses the organization's."`
ManagerID string `json:"managerId" doc:"Who approves this person's time. Empty defers to the host's directory."`
OvertimeExempt bool `json:"overtimeExempt"`
PayrollID string `json:"payrollId" maxLength:"64"`
Active bool `json:"active" doc:"Inactive people are left out of payroll reports and exceptions."`
// SubmitsTimesheets is this person's own choice; absent or null follows the workspace.
SubmitsTimesheets *bool `` /* 155-byte string literal not displayed */
// HolidayPay is this person's own choice; absent or null follows the workspace.
HolidayPay *bool `` /* 141-byte string literal not displayed */
}
PersonUpdate is what an admin sets on a person.
type Project ¶
type Project struct {
ID uuid.UUID `json:"id"`
CustomerID *uuid.UUID `json:"customerId,omitempty" doc:"Absent for internal work."`
CustomerName string `json:"customerName" doc:"Empty for internal work."`
Name string `json:"name"`
Code string `json:"code" doc:"A charge code or contract number."`
Billable bool `json:"billable"`
Archived bool `json:"archived" doc:"The project itself is archived."`
// CustomerArchived means the project takes no new time either way.
CustomerArchived bool `json:"customerArchived"`
}
Project is a body of work that time is tagged with: for a customer, or internal when it has none.
type ProjectHours ¶
type ProjectHours struct {
CustomerName string `json:"customerName"`
ProjectID string `json:"projectId" doc:"Empty for time with no project."`
ProjectName string `json:"projectName"`
ProjectCode string `json:"projectCode"`
Billable bool `json:"billable"`
PersonID string `json:"personId"`
PersonName string `json:"personName"`
Hours float64 `json:"hours"`
}
ProjectHours is time on one project by one person, for the project report.
type ProjectInput ¶
type ProjectInput struct {
CustomerID *uuid.UUID `json:"customerId,omitempty" doc:"Absent for internal work."`
Name string `json:"name" minLength:"1" maxLength:"120"`
Code string `json:"code,omitempty" maxLength:"64" doc:"A charge code or contract number."`
Billable bool `json:"billable"`
Archived bool `json:"archived,omitempty"`
}
ProjectInput is what an admin sets on a project.
type RecentWork ¶ added in v0.24.0
type RecentWork struct {
Note string `json:"note"`
ProjectID *uuid.UUID `json:"projectId,omitempty"`
}
RecentWork is something a person has tracked before: a note and its project.
type Reminder ¶
type Reminder struct {
PersonID string
Kind string
// Key identifies what it is about, so it is sent once: the entry of a
// running clock, or the first day of a pay period.
Key string
// Hours is how long the clock has run, for a running clock.
Hours float64
// Period is the pay period whose timesheet is due.
Period Period
}
Reminder is a nudge for one person about their own time.
type Reminders ¶
type Reminders struct {
// contains filtered or unexported fields
}
Reminders is the periodic job that nudges people through the host's notifications.
func NewReminders ¶
NewReminders returns the job. It does nothing until Bind.
func (*Reminders) Register ¶
func (r *Reminders) Register(workers *hopper.Workers) hopper.PeriodicJob
Register adds the job's worker and returns its schedule for hopper.Config.Periodic.
type Scheme ¶ added in v0.4.0
Scheme is one of the two: the page's seed, and optionally the sidebar's.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is Timeclock's payroll data and its rules. Every method takes the Actor it acts for and refuses what that person may not do.
func (*Service) Absences ¶ added in v0.25.0
Absences is everyone's approved time off on the days from..to, for those still active, by day.
func (*Service) Activity ¶ added in v0.2.0
Activity lists, for everyone whose time actor may see and who still tracks time, what they are on now and their hours today and this workweek. People with a running clock come first.
func (*Service) Audit ¶
func (s *Service) Audit(ctx context.Context, actor Actor, q AuditQuery) ([]AuditEntry, bool, error)
Audit lists a page of changes, newest first, and whether older ones follow. Only an auditor reads it: the host decides who, and being an admin is not enough.
func (*Service) AuditPeople ¶ added in v0.27.0
AuditPeople names everyone in the workspace, for an auditor reading the log. An auditor need not be an admin, and People shows them only their own and their reports'.
func (*Service) CalendarFeed ¶ added in v0.25.0
CalendarFeed says whether actor has a calendar feed.
func (*Service) CalendarFeedOwner ¶ added in v0.25.0
CalendarFeedOwner is whose feed a secret opens, in any workspace: a feed is fetched by a calendar app, which says nothing about where it is.
func (*Service) CancelTimeOff ¶
CancelTimeOff removes time off on a day whose timesheet isn't submitted.
func (*Service) ClockIn ¶
func (s *Service) ClockIn(ctx context.Context, actor Actor, projectID *uuid.UUID, note string) (Entry, error)
ClockIn starts the actor's clock. Required fields can be filled in while it runs.
func (*Service) CreateEntry ¶
CreateEntry records a finished stretch of work by hand.
func (*Service) Decide ¶
func (s *Service) Decide(ctx context.Context, actor Actor, id uuid.UUID, approve bool, note string) (Timesheet, error)
Decide approves a submitted timesheet, or sends it back to its person with a note, which unlocks its time.
func (*Service) DecideTimeOff ¶
func (s *Service) DecideTimeOff(ctx context.Context, actor Actor, id uuid.UUID, approve bool, note string) (TimeOff, error)
DecideTimeOff approves or rejects pending time off.
func (*Service) DeleteCustomer ¶
DeleteCustomer removes a customer with no projects.
func (*Service) DeleteEntry ¶
DeleteEntry removes an entry.
func (*Service) DeleteHoliday ¶ added in v0.15.0
DeleteHoliday removes a holiday whose days are outside settled timesheets.
func (*Service) DeleteProject ¶
DeleteProject removes a project no time was recorded on.
func (*Service) DueReminders ¶
DueReminders finds what people should be nudged about now and haven't been: a clock running past the long-entry limit, and a timesheet for the last pay period that was never submitted. Each is recorded as sent, so a later call doesn't return it again.
func (*Service) EnsureWorkspace ¶ added in v0.4.0
EnsureWorkspace returns the workspace with the given key, making it, with default settings, the first time it is asked for.
func (*Service) Entries ¶
func (s *Service) Entries(ctx context.Context, actor Actor, personID string, from, to Date) ([]Entry, error)
Entries lists a person's time that touches the days from..to, oldest first.
func (*Service) Exceptions ¶
Exceptions lists what payroll should look at in the pay period containing day, for the people whose time actor may see.
func (*Service) Holidays ¶ added in v0.15.0
Holidays lists the company's holidays by their first day.
func (*Service) HoursByDayAndProject ¶ added in v0.2.0
func (s *Service) HoursByDayAndProject(ctx context.Context, actor Actor, from, to Date, mine bool) ([]DayProjectHours, error)
HoursByDayAndProject adds up time on the days from..to by day and project: the caller's own when mine is set, and otherwise that of everyone whose time they may see. A running clock counts up to now. Time is cut at each midnight where the person is. Unlike worked hours, overlapping entries each count in full, so every project shows all the time recorded on it.
func (*Service) In ¶ added in v0.4.0
In returns the service for one workspace. Everything it reads and writes is that workspace's.
func (*Service) Meetings ¶ added in v0.22.0
func (s *Service) Meetings(ctx context.Context, actor Actor, meetings []string) (map[string]MeetingChoice, error)
Meetings are the projects the actor copies these meetings to, for those they have chosen one for. A project archived since is no choice: the next copy asks again.
func (*Service) NewCalendarFeed ¶ added in v0.25.0
func (s *Service) NewCalendarFeed(ctx context.Context, actor Actor, c FeedContents) (string, CalendarFeedStatus, error)
NewCalendarFeed makes actor a calendar feed listing c, and returns its secret. Any feed they had stops working.
func (*Service) PendingTimeOff ¶
PendingTimeOff lists the time off waiting for actor's decision: their reports', or everyone's for an admin.
func (*Service) People ¶
People lists the people whose time actor may see: everyone for an admin, otherwise the actor and their reports.
func (*Service) ProjectReport ¶
func (s *Service) ProjectReport(ctx context.Context, actor Actor, from, to Date) ([]ProjectHours, error)
ProjectReport adds up finished time on the days from..to by project and person, for the people whose time actor may see. Time is cut at the first and last midnight where each person is, so an entry across one counts only its part inside.
func (*Service) Projects ¶
Projects lists internal projects, then the rest by customer, each by name, with archived ones when asked: its own, and those of archived customers.
func (*Service) RecentWork ¶ added in v0.24.0
RecentWork lists the notes the caller has tracked, each with the project it was on, the most recently worked first, so the clock can suggest them again.
func (*Service) RememberMeeting ¶ added in v0.22.0
func (s *Service) RememberMeeting(ctx context.Context, actor Actor, meeting string, projectID *uuid.UUID) error
RememberMeeting keeps the project the actor copies a meeting to.
func (*Service) Reopen ¶
func (s *Service) Reopen(ctx context.Context, actor Actor, id uuid.UUID, note string) (Timesheet, error)
Reopen unlocks a timesheet so its time can be corrected: its person can take back one that is still waiting, and a manager or admin can send back one that was approved.
func (*Service) RequestTimeOff ¶
func (s *Service) RequestTimeOff(ctx context.Context, actor Actor, in TimeOffInput) ([]TimeOff, error)
RequestTimeOff records time off on each day of a run. It waits for a decision when the organization approves time off, and is approved at once when it doesn't.
func (*Service) SaveCustomer ¶
func (s *Service) SaveCustomer(ctx context.Context, actor Actor, id uuid.UUID, name string, archived bool) (Customer, error)
SaveCustomer creates a customer, or with an id renames or archives one.
func (*Service) SaveHoliday ¶ added in v0.15.0
func (s *Service) SaveHoliday(ctx context.Context, actor Actor, id uuid.UUID, in HolidayInput) (Holiday, error)
SaveHoliday adds a holiday, or with an id changes one. Only the days whose pay changes need to be outside settled timesheets.
func (*Service) SaveProject ¶
func (s *Service) SaveProject(ctx context.Context, actor Actor, id uuid.UUID, in ProjectInput) (Project, error)
SaveProject creates a project, or with an id changes one.
func (*Service) SetAdmin ¶ added in v0.11.0
SetAdmin grants a person admin in Timeclock, or takes the grant back. Someone the host makes an admin stays one: only the host can change that. No one takes their own admin away, so a workspace can't lock itself out.
func (*Service) SetCalendarFeed ¶ added in v0.25.0
func (s *Service) SetCalendarFeed(ctx context.Context, actor Actor, c FeedContents) (CalendarFeedStatus, error)
SetCalendarFeed changes what actor's calendar feed lists, at the same address: subscribers see it when they next fetch it.
func (*Service) SetOwnTimezone ¶ added in v0.2.0
SetOwnTimezone sets the time zone the actor's own days are cut in. Time in a submitted timesheet keeps the days it was submitted with.
func (*Service) SetTheme ¶ added in v0.4.0
SetTheme sets the workspace's look. An empty theme goes back to the host's, or Timeclock's own.
func (*Service) StopCalendarFeed ¶ added in v0.25.0
StopCalendarFeed turns actor's calendar feed off.
func (*Service) Submit ¶
func (s *Service) Submit(ctx context.Context, actor Actor, personID string, day Date) (PeriodSummary, error)
Submit states that a person's pay period containing day is complete, which locks its time. It waits for a decision when the organization approves timesheets, and is approved at once when it doesn't.
func (*Service) Summary ¶
func (s *Service) Summary(ctx context.Context, actor Actor, personID string, day Date) (PeriodSummary, error)
Summary returns a person's pay period containing day.
func (*Service) Switch ¶ added in v0.2.0
func (s *Service) Switch(ctx context.Context, actor Actor, projectID *uuid.UUID, note string) (Entry, error)
Switch moves the actor's running clock to other work without stopping it: the time so far stays on what it was recorded against, and the clock goes on, from this instant, against the given project and note.
func (*Service) Sync ¶
Sync records the host's current answer about a person and returns them as an Actor. It is called for the caller of every request, so the people table always has everyone who has used Timeclock.
func (*Service) SyncAll ¶
SyncAll records everyone in the host's directory, so admins can assign managers and report on people who haven't opened Timeclock yet.
func (*Service) Team ¶
Team returns the pay period containing day for everyone whose time actor may see and who still tracks time.
func (*Service) Theme ¶ added in v0.4.0
Theme returns the look an admin set for the workspace; its schemes are nil where they set none.
func (*Service) TimeOff ¶
func (s *Service) TimeOff(ctx context.Context, actor Actor, personID string, from, to Date) ([]TimeOff, error)
TimeOff lists a person's time off on the days from..to.
func (*Service) UpdateEntry ¶
func (s *Service) UpdateEntry(ctx context.Context, actor Actor, id uuid.UUID, in EntryInput) (Entry, error)
UpdateEntry changes an entry. Giving a running clock an end stops it.
func (*Service) UpdatePerson ¶
func (s *Service) UpdatePerson(ctx context.Context, actor Actor, id string, in PersonUpdate) (Person, error)
UpdatePerson sets a person's manager and payroll details.
func (*Service) UpdateSettings ¶
UpdateSettings changes how payroll runs. Timesheets already submitted keep the pay period they were submitted for.
type Settings ¶
type Settings struct {
Timezone string `` /* 136-byte string literal not displayed */
PayCycle PayCycle `json:"payCycle" enum:"weekly,biweekly,semimonthly,monthly"`
CycleAnchor Date `json:"cycleAnchor" format:"date" doc:"The first day of some weekly or biweekly pay period."`
WeekStart int `json:"weekStart" minimum:"0" maximum:"6" doc:"The day the workweek starts, for overtime: 0 is Sunday."`
OvertimeWeeklyHours float64 `` /* 131-byte string literal not displayed */
SubmitTimesheets bool `` /* 181-byte string literal not displayed */
HolidayPay bool `json:"holidayPay" doc:"People are paid for company holidays, unless set otherwise for them."`
ApproveTimesheets bool `json:"approveTimesheets" doc:"A submitted timesheet waits for the person's manager or an admin."`
ApproveTimeOff bool `json:"approveTimeOff" doc:"Time off waits for the person's manager or an admin."`
RequireDescription bool `json:"requireDescription" doc:"Every time entry has a description."`
RequireProject bool `json:"requireProject" doc:"Every time entry names a project."`
LongEntryHours float64 `json:"longEntryHours" exclusiveMinimum:"0" maximum:"24" doc:"An entry or a running clock longer than this is an exception."`
AllowPlannedTime bool `` /* 228-byte string literal not displayed */
}
Settings is how the organization runs payroll.
func (Settings) LocationOf ¶ added in v0.2.0
LocationOf is the time zone a person's days and workweeks are cut in: their own, or the organization's when they have none.
func (Settings) Overtime ¶
func (s Settings) Overtime(exempt bool) OvertimeRule
Overtime is the settings' overtime rule for a person.
type TimeOff ¶
type TimeOff struct {
ID uuid.UUID `json:"id"`
PersonID string `json:"personId"`
Kind string `json:"kind" enum:"vacation,sick"`
Day Date `json:"day" format:"date"`
Hours float64 `json:"hours"`
Note string `json:"note"`
Status string `json:"status" enum:"pending,approved,rejected"`
DecidedBy string `json:"decidedBy,omitempty"`
DecidedByName string `json:"decidedByName,omitempty"`
DecidedAt *time.Time `json:"decidedAt,omitempty"`
DecisionNote string `json:"decisionNote,omitempty"`
Locked bool `json:"locked" doc:"Its day is in a submitted or approved timesheet, so it can't be removed."`
}
TimeOff is vacation or sick hours on one day.
type TimeOffInput ¶
type TimeOffInput struct {
PersonID string `json:"personId,omitempty" doc:"Whose time off. Defaults to the caller; a manager or admin can record it for someone else."`
Kind string `json:"kind" enum:"vacation,sick"`
From Date `json:"from" format:"date"`
To Date `json:"to" format:"date" doc:"The last day off; the same as from for one day."`
Hours float64 `json:"hours" exclusiveMinimum:"0" maximum:"24" doc:"Hours off on each day."`
Weekends bool `json:"weekends,omitempty" doc:"Include Saturdays and Sundays in the run."`
Note string `json:"note,omitempty" maxLength:"2000"`
}
TimeOffInput is a request for time off on a run of days.
type Timesheet ¶
type Timesheet struct {
ID uuid.UUID `json:"id"`
PersonID string `json:"personId"`
Period Period `json:"period"`
Status string `json:"status" enum:"submitted,approved,rejected"`
SubmittedAt time.Time `json:"submittedAt"`
DecidedBy string `json:"decidedBy,omitempty" doc:"Who approved it or sent it back; the person themselves when they took it back."`
DecidedByName string `json:"decidedByName,omitempty"`
DecidedAt *time.Time `json:"decidedAt,omitempty"`
DecisionNote string `json:"decisionNote,omitempty"`
}
Timesheet is a person's statement that a pay period's time is complete.
type Toggl ¶ added in v0.5.0
type Toggl struct {
// contains filtered or unexported fields
}
Toggl is the company migration bridge. Credentials are encrypted with a key kept outside the database; associated data binds ciphertext to its workspace.
func (*Toggl) Disconnect ¶ added in v0.5.0
func (*Toggl) Register ¶ added in v0.5.0
func (t *Toggl) Register(workers *hopper.Workers) hopper.PeriodicJob
func (*Toggl) RequestSync ¶ added in v0.5.0
type TogglIssue ¶ added in v0.5.0
type TogglIssue struct {
EntryID uuid.UUID `json:"entryId"`
PersonID string `json:"personId"`
RemoteID *int64 `json:"remoteId,omitempty"`
Kind string `json:"kind"`
Version string `json:"version"`
Local togglState `json:"local"`
Remote togglState `json:"remote"`
// TimeOff is set for Toggl entries on the vacation or sick project, which
// sync to time off on a day rather than to an entry.
TimeOff *TogglTimeOff `json:"timeOff,omitempty"`
}
type TogglMapping ¶ added in v0.5.0
type TogglPreview ¶ added in v0.5.0
type TogglPreview struct {
Workspaces []toggl.Workspace `json:"workspaces"`
Users []toggl.User `json:"users"`
Projects []TogglProject `json:"projects"`
Suggested []TogglMapping `json:"suggested"`
}
type TogglProject ¶ added in v0.15.0
type TogglProject struct {
ID int64 `json:"id"`
Name string `json:"name"`
Active bool `json:"active"`
}
TogglProject is a project in the Toggl workspace, to choose roles from.
type TogglResolution ¶ added in v0.5.0
type TogglResolution struct {
Choice string `json:"choice" enum:"local,remote,retry,link"`
Version string `json:"version"`
RemoteID int64 `json:"remoteId,omitempty"`
}
Resolve records an explicit choice against the exact versions the admin saw. The worker still validates payroll locks and rechecks Toggl before pushing.
type TogglRoles ¶ added in v0.15.0
type TogglRoles struct {
HolidayProject int64 `json:"holidayProject,omitempty" minimum:"0" doc:"Entries on it are left out: company holidays pay that time."`
VacationProject int64 `json:"vacationProject,omitempty" minimum:"0" doc:"Entries on it become vacation."`
SickProject int64 `json:"sickProject,omitempty" minimum:"0" doc:"Entries on it become sick time."`
}
TogglRoles are the Toggl projects that record time away rather than work. Each applies to entries from the day it was chosen; zero is none.
type TogglSetup ¶ added in v0.5.0
type TogglSetup struct {
Token string `json:"token" maxLength:"256"`
WorkspaceID int64 `json:"workspaceId" minimum:"1"`
From string `json:"from" doc:"Optional start date (YYYY-MM-DD). Empty imports all history."`
People []TogglMapping `json:"people" minItems:"1" maxItems:"1000"`
TogglRoles
}
type TogglStatus ¶ added in v0.5.0
type TogglStatus struct {
HistoryComplete bool `json:"historyComplete"`
HistoryThrough string `json:"historyThrough"`
Available bool `json:"available"`
Connected bool `json:"connected"`
WorkspaceID int64 `json:"workspaceId"`
From string `json:"from"`
LastSync *time.Time `json:"lastSync,omitempty"`
NextSync *time.Time `json:"nextSync,omitempty"`
Error string `json:"error"`
// RateLimitedUntil is when Toggl's API limit allows Sync now again.
RateLimitedUntil *time.Time `json:"rateLimitedUntil,omitempty"`
People []TogglMapping `json:"people"`
TogglRoles
HolidayFrom string `json:"holidayFrom,omitempty"`
VacationFrom string `json:"vacationFrom,omitempty"`
SickFrom string `json:"sickFrom,omitempty"`
HolidayName string `json:"holidayName,omitempty" doc:"The project's name once a sync has brought it in."`
VacationName string `json:"vacationName,omitempty"`
SickName string `json:"sickName,omitempty"`
Issues []TogglIssue `json:"issues"`
}
type TogglTimeOff ¶ added in v0.15.0
type TogglTimeOff struct {
Kind string `json:"kind" enum:"vacation,sick"`
Day Date `json:"day" format:"date"`
Hours float64 `json:"hours" doc:"What the Toggl entries add up to."`
}
TogglTimeOff is the time off a day's Toggl entries add up to.