goharvest

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 21, 2024 License: Apache-2.0 Imports: 9 Imported by: 0

README

Go Harvest

This package provides a Go library that can interact with the Harvest API. The progress toward 100% compatibility can be found below.

Usage

The intended usage of this client is as follows:

package main

import (
    harvest "github.com/pmwals09/go-harvest"
)

func main() {
    timeEntries := client.ReadTimeEntries()

    client := harvest.NewClient(token, accountID, userAgent)
    newTimeEntry := goharvest.CreateTimeEntryBodyDuration{
        UserID: &user.ID,
        ProjectID: project.Project.ID,
        TaskID: project.TaskAssignments[0].Task.ID,
        SpentDate: goharvest.Date{Time: startTime}
        Hours: &duration,
        Notes: "These are the notes"
        ExternalReference: nil,
    }
    timeEntryRes, err := client.CreateTimeEntry(newTimeEntry)
}

Most of the endpoints in question require authentication. Harvest allows for two types of authentication - the only one fully supported here is thePersonal Access Token (PAT). You must have a valid HARVEST_PAT environment variable set in order to use this library. If you would like to use OAuth, you will need to handle the OAuth flow yourself, including token renewal - the focus of this module is API coverage.

Project Structure

The sole package intended to be used is the goharvest module. This module consists of the Client that handles making the API requests, and the various types needed to create or utilize those requests.

FAQ

Yes, you really do, according to Harvest's documentation. You can't use mine, sorry.

API Coverage

Authentication

Documentation: Authentication

  • Personal Access Token
  • OAuth2
    • Possibly in the future. For the moment the client simply accepts and uses a token, and would rely on the application to manage the OAuth flow.
Clients API

Documentation:

  • Client Contacts

  • Clients

  • GET /v2/contacts

  • GET /v2/contacts/{CONTACT_ID}

  • POST /v2/contacts

  • PATCH /v2/contacts/{CONTACT_ID}

  • DELETE /v2/contacts/{CONTACT_ID}

  • GET /v2/clients

  • GET /v2/clients/{CLIENT_ID}

  • POST /v2/clients

  • PATCH /v2/clients/{CLIENT_ID}

  • DELETE /v2/clients/{CLIENT_ID}

Company Settings

Documentation: Company

  • GET /v2/company
  • PATCH /v2/company
Invoices API

Documentation:

  • Invoice Messages

  • Invoice Payments

  • Invoices

  • Invoice Item Categories

  • GET /v2/invoices/{INVOICE_ID}/messages

  • POST /v2/invoices/{INVOICE_ID}/messages

  • GET /v2/invoices/{INVOICE_ID}/messages/new

  • DELETE /v2/invoices/{INVOICE_ID}/messages/{message_ID}

  • GET /v2/invoices/{INVOICE_ID}/payments

  • POST /v2/invoices/{INVOICE_ID}/payments

  • DELETE /v2/invoices/{INVOICE_ID}/payments/{PAYMENT_ID}

  • GET /v2/invoices

  • GET /v2/invoices/{INVOICE_ID}

  • POST /v2/invoices

  • PATCH /v2/invoices/{INVOICE_ID}

  • DELETE /v2/invoices/{INVOICE_ID}

  • GET /v2/invoice_item_categories

  • GET /v2/invoice_item_categories/{INVOICE_ITEM_CATEGORY_ID}

  • POST /v2/invoice_item_categories

  • PATCH /v2/invoice_item_categories/{INVOICE_ITEM_CATEGORY_ID}

  • DELETE /v2/invoice_item_categories/{INVOICE_ITEM_CATEGORY_ID}

Estimates API

Documentation:

  • Estimate Messages

  • Estimates

  • Estimate Item Categories

  • GET /v2/estimates/{estimate_ID}/messages

  • POST /v2/estimates/{estimate_ID}/messages

  • DELETE /v2/estimates/{estimate_ID}/messages/{message_ID}

  • GET /v2/estimates

  • GET /v2/estimates/{ESTIMATE_ID}

  • POST /v2/estimates

  • PATCH /v2/estimates/{ESTIMATE_ID}

  • DELETE /v2/estimates/{ESTIMATE_ID}

  • GET /v2/estimate_item_categories

  • GET /v2/estimate_item_categories/{ESTIMATE_ITEM_CATEGORY_ID}

  • POST /v2/estimate_item_categories

  • PATCH /v2/estimate_item_categories/{ESTIMATE_ITEM_CATEGORY_ID}

  • DELETE /v2/estimate_item_categories/{ESTIMATE_ITEM_CATEGORY_ID}

Expenses API

Documentation:

  • Expenses

  • Expense Categories

  • GET /v2/expenses

  • GET /v2/expenses/{EXPENSE_ID}

  • POST /v2/expenses

  • PATCH /v2/expenses/{EXPENSE_ID}

  • DELETE /v2/expenses/{EXPENSE_ID}

  • GET /v2/expense_categories

  • GET /v2/expense_categories/{EXPENSE_CATEGORY_ID}

  • POST /v2/expense_categories

  • PATCH /v2/expense_categories/{EXPENSE_CATEGORY_ID}

  • DELETE /v2/expense_categories/{EXPENSE_CATEGORY_ID}

Tasks API

Documentation: Tasks

  • GET /v2/tasks
  • GET /v2/tasks/{TASK_ID}
  • POST /v2/tasks
  • PATCH /v2/tasks/{TASK_ID}
  • DELETE /v2/tasks/{TASK_ID}
Timesheets API

Documentation: Time Entries

  • GET /v2/time_entries
  • GET /v2/time_entries/{TIME_ENTRY_ID}
  • POST /v2/time_entries
  • PATCH /v2/time_entries/{TIME_ENTRY_ID}
  • DELETE /v2/time_entries/{TIME_ENTRY_ID}/external_reference
  • DELETE /v2/time_entries/{TIME_ENTRY_ID}
  • PATCH /v2/time_entries/{TIME_ENTRY_ID}/restart
  • PATCH /v2/time_entries/{TIME_ENTRY_ID}/stop
Projects API

Documentation:

  • Project User Assignments

  • Project Task Assignments

  • Projects

  • GET /v2/user_assignments

  • GET /v2/projects/{PROJECT_ID}/user_assignments

  • GET /v2/projects/{PROJECT_ID}/user_assignments/{USER_ASSIGNMENT_ID}

  • POST /v2/projects/{PROJECT_ID}/user_assignments

  • PATCH /v2/projects/{PROJECT_ID}/user_assignments/{USER_ASSIGNMENT_ID}

  • DELETE /v2/projects/{PROJECT_ID}/user_assignments/{USER_ASSIGNMENT_ID}

  • GET /v2/task_assignments

  • GET /v2/projects/{PROJECT_ID}/task_assignments

  • GET /v2/projects/{PROJECT_ID}/task_assignments/{TASK_ASSIGNMENT_ID}

  • POST /v2/projects/{PROJECT_ID}/task_assignments

  • PATCH /v2/projects/{PROJECT_ID}/task_assignments/{TASK_ASSIGNMENT_ID}

  • DELETE /v2/projects/{PROJECT_ID}/task_assignments/{TASK_ASSIGNMENT_ID}

  • GET /v2/projects

  • GET /v2/projects/{PROJECT_ID}

  • POST /v2/projects

  • PATCH /v2/projects/{PROJECT_ID}

  • DELETE /v2/projects/{PROJECT_ID}

Roles API

Documentation: Roles

  • GET /v2/roles
  • GET /v2/roles/{ROLE_ID}
  • POST /v2/roles
  • PATCH /v2/roles/{ROLE_ID}
  • DELETE /v2/roles/{ROLE_ID}
Users API

Documentation:

  • User Teammates

  • User Billable Rates

  • User Cost Rates

  • User Project Assignments

  • Users

  • GET /v2/users/{USER_ID}/teammates

  • PATCH /v2/users/{USER_ID}/teammates

  • GET /v2/users/{USER_ID}/billable_rates

  • GET /v2/users/{USER_ID}/billable_rates/{billable_RATE_ID}

  • POST /v2/users/{USER_ID}/billable_rates

  • GET /v2/users/{USER_ID}/cost_rates

  • GET /v2/users/{USER_ID}/cost_rates/{COST_RATE_ID}

  • POST /v2/users/{USER_ID}/cost_rates

  • GET /v2/users/{USER_ID}/project_assignments

  • GET /v2/users/me/project_assignments

  • GET /v2/users

  • GET /v2/users/me

  • GET /v2/users/{USER_ID}

  • POST /v2/users

  • PATCH /v2/users/{USER_ID}

  • PATCH /v2/users/{USER_ID}

  • DELETE /v2/users/{USER_ID}

Reports API

Documentation:

  • Expense Reports

  • Uninvoiced Report

  • Time Reports

  • Project Budget Report

  • GET /v2/reports/expenses/clients

  • GET /v2/reports/expenses/projects

  • GET /v2/reports/expenses/categories

  • GET /v2/reports/expenses/team

  • GET /v2/reports/uninvoiced

  • GET /v2/reports/time/clients

  • GET /v2/reports/time/projects

  • GET /v2/reports/time/tasks

  • GET /v2/reports/time/team

  • GET /v2/reports/project_budget

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// The base path of the Harvest API, as detailed on Harvest's
	// documentation site
	BasePath string

	// The token to use when making requests, provided by the application.
	// Harvest provides OAuth or PAT style authentication.
	Token string

	// The HTTP Client that does the heavy lifting
	Client http.Client

	// The AccountID against which the client will make requests.
	AccountID string

	// The UserAgent to use when making requests. This is a string that
	// typically takes the form of "<appName> (<contact>)"; i.e.:
	// "MyHarvestApp (https://www.myharvestapp.com/contact)" or
	// "MyHarvestApp (myemail@email.com)"
	UserAgent string
}

func NewClient

func NewClient(PAT string, accountID string, userAgent string) *Client

Create a new Client with the provided token, account ID, and User-Agent string

func (*Client) CreateTimeEntry

func (c *Client) CreateTimeEntry(body CreateTimeEntryBody) (TimeEntry, error)

Creates a new time entry object. Returns a time entry object and a 201 Created response code if the call succeeded.

This same function is used to create time entries when an account is configured to track time via duration or via start and end time. Harvest will create the time entry accordingly depending on the account settings. You can verify this by visiting the Settings page in your Harvest account or by checking if wants_timestamp_timers is false in the Company API.

If you provide the wrong type of body to this function - i.e., for the type opposite the type expected according to the settings - then this endpoint will create a running timer.

func (*Client) Delete

func (c *Client) Delete(urlTail string) error

func (*Client) DeleteTimeEntry

func (c *Client) DeleteTimeEntry(id uint64) error

Delete a time entry. Deleting a time entry is only possible if it’s not closed and the associated project and task haven’t been archived. However, Admins can delete closed entries. Returns a 200 OK response code if the call succeeded.

func (*Client) Get

func (c *Client) Get(urlTail string) (*http.Response, error)

Make a GET request to the client's BasePath + the provided urlTail

func (*Client) GetCompany

func (c *Client) GetCompany() (Company, error)

Retrieves the company for the currently authenticated user. Returns a company object and a 200 OK response code.

func (*Client) GetMe

func (c *Client) GetMe() (User, error)

Retrieves the currently authenticated user. Returns a user object and a 200 OK response code.

func (*Client) GetMyProjectAssignments

func (c *Client) GetMyProjectAssignments(params GetProjectAssignmentParameters) (ProjectAssignmentResponse, error)

Returns a list of your active project assignments for the currently authenticated user. The project assignments are returned sorted by creation date, with the most recently created project assignments appearing first.

func (*Client) GetTimeEntries

func (c *Client) GetTimeEntries(params GetTimeEntryParameters) (TimeEntryResponse, error)

Returns a list of time entries. The time entries are returned sorted by spent_date date. At this time, the sort option can’t be customized.

func (*Client) GetTimeEntry

func (c *Client) GetTimeEntry(id uint64) (TimeEntry, error)

Retrieves the time entry with the given ID. Returns a time entry object and a 200 OK response code if a valid identifier was provided.

func (*Client) Patch

func (c *Client) Patch(urlTail string, body any) (*http.Response, error)

func (*Client) Post

func (c *Client) Post(urlTail string, body any) (*http.Response, error)

Make a POST request to the client's BasePath + the provided urlTail, using the provided request body.

func (*Client) RestartTimeEntryTimer

func (c *Client) RestartTimeEntryTimer(id uint64) (TimeEntry, error)

Restarting a time entry is only possible if it isn’t currently running. Returns a 200 OK response code if the call succeeded.

func (*Client) StopTimeEntryTimer

func (c *Client) StopTimeEntryTimer(id uint64) (TimeEntry, error)

Stopping a time entry is only possible if it’s currently running. Returns a 200 OK response code if the call succeeded.

func (*Client) UpdateCompany

func (c *Client) UpdateCompany(params CompanyUpdateParameters) (Company, error)

Updates the company setting the values of the parameters passed. Any parameters not provided will be left unchanged. Returns a company object and a 200 OK response code if the call succeeded.

func (*Client) UpdateTimeEntry

func (c *Client) UpdateTimeEntry(timeEntryId uint64, body UpdateTimeEntryBody) (TimeEntry, error)

Updates the specific time entry by setting the values of the parameters passed. Any parameters not provided will be left unchanged. Returns a time entry object and a 200 OK response code if the call succeeded.

type Company

type Company struct {
	// The Harvest URL for the company.
	BaseUri string `json:"base_uri" url:"base_uri,omitempty"`

	// The Harvest domain for the company.
	FullDomain string `json:"full_domain" url:"full_domain,omitempty"`

	// The name of the company.
	Name string `json:"name" url:"name,omitempty"`

	// Whether the company is active or archived.
	IsActive bool `json:"is_active" url:"is_active,omitempty"`

	// The weekday used as the start of the week. Returns one of: Saturday,
	// Sunday, or Monday.
	WeekStartDay string `json:"week_start_day" url:"week_start_day,omitempty"`

	// Whether time is tracked via duration or start and end times.
	WantsTimestampTimers bool `json:"wants_timestamp_timers" url:"wants_timestamp_timers,omitempty"`

	// The format used to display time in Harvest. Returns either decimal or
	// hours_minutes.
	TimeFormat string `json:"time_format" url:"time_format,omitempty"`

	// The format used to display date in Harvest. Returns one of: %m/%d/%Y,
	// %d/%m/%Y, %Y-%m-%d, %d.%m.%Y,.%Y.%m.%d or %Y/%m/%d.
	DateFormat string `json:"date_format" url:"date_format,omitempty"`

	// The type of plan the company is on. Examples: trial, free, or simple-v4
	PlanType string `json:"plan_type" url:"plan_type,omitempty"`

	// Used to represent whether the company is using a 12-hour or 24-hour clock.
	// Returns either 12h or 24h.
	Clock string `json:"clock" url:"clock,omitempty"`

	// How to display the currency code when formatting currency. Returns one of:
	// iso_code_none, iso_code_before, or iso_code_after.
	CurrencyCodeDisplay string `json:"currency_code_display" url:"currency_code_display,omitempty"`

	// How to display the currency symbol when formatting currency. Returns one
	// of: symbol_none, symbol_before, or symbol_after.
	CurrencySymbolDisplay string `json:"currency_symbol_display" url:"currency_symbol_display,omitempty"`

	// Symbol used when formatting decimals.
	DecimalSymbol string `json:"decimal_symbol" url:"decimal_symbol,omitempty"`

	// Separator used when formatting numbers.
	ThousandsSeparator string `json:"thousands_separator" url:"thousands_separator,omitempty"`

	// The color scheme being used in the Harvest web client.
	ColorScheme string `json:"color_scheme" url:"color_scheme,omitempty"`

	// The weekly capacity in seconds.
	WeeklyCapacity int `json:"weekly_capacity" url:"weekly_capacity,omitempty"`

	// Whether the expense module is enabled.
	ExpenseFeature bool `json:"expense_feature" url:"expense_feature,omitempty"`

	// Whether the invoice module is enabled.
	InvoiceFeature bool `json:"invoice_feature" url:"invoice_feature,omitempty"`

	// Whether the estimate module is enabled.
	EstimateFeature bool `json:"estimate_feature" url:"estimate_feature,omitempty"`

	// Whether the approval module is enabled.
	ApprovalFeature bool `json:"approval_feature" url:"approval_feature,omitempty"`
}

type CompanyUpdateParameters

type CompanyUpdateParameters struct {
	// Whether time is tracked via duration or start and end times.
	WantsTimestampTimers *bool `json:"wants_timestamp_timers" url:"wants_timestamp_timers,omitempty"`

	// The weekly capacity in seconds.
	WeeklyCapacity *int `json:"weekly_capacity" url:"weekly_capacity,omitempty"`
}

type CreateTimeEntryBody

type CreateTimeEntryBody interface {
	GetTimeEntryBodyParams() string
	IsValid() bool
}

type CreateTimeEntryBodyDuration

type CreateTimeEntryBodyDuration struct {
	// The ID of the user to associate with the time entry. Defaults to the
	// currently authenticated user’s ID. - optional
	UserID *int `json:"user_id" url:"user_id,omitempty"`

	// The ID of the project to associate with the time entry. - required
	ProjectID int `json:"project_id" url:"project_id,omitempty"`

	// The ID of the task to associate with the time entry. - required
	TaskID int `json:"task_id" url:"task_id,omitempty"`

	// The ISO 8601 formatted date the time entry was spent. - required
	SpentDate Date `json:"spent_date" url:"spent_date,omitempty"`

	// The current amount of time tracked. If provided, the time entry will
	// be created with the specified hours and is_running will be set to
	// false. If not provided, hours will be set to 0.0 and is_running will
	// be set to true. - optional
	Hours *float64 `json:"hours" url:"hours,omitempty"`

	// Any notes to be associated with the time entry. - optional
	Notes string `json:"notes" url:"notes,omitempty"`

	// An object containing the id, group_id, account_id, and permalink of
	// the external reference. - optional
	ExternalReference *ExternalReference `json:"external_reference" url:"external_reference,omitempty"`
}

The body required to create a time entry using the duration of an entry. If a duration is not provided and the company settings are such that it accepts time entries as durations, then an entry with a duration of "0.0" will be created.

If, on the other hand, your company settings are such that users enter time with start and end times, then this will start a timer the begins at the current time.

func (CreateTimeEntryBodyDuration) GetTimeEntryBodyParams

func (b CreateTimeEntryBodyDuration) GetTimeEntryBodyParams() string

func (CreateTimeEntryBodyDuration) IsValid

func (b CreateTimeEntryBodyDuration) IsValid() bool

type CreateTimeEntryBodyStartEnd

type CreateTimeEntryBodyStartEnd struct {
	// The ID of the user to associate with the time entry. Defaults to the
	// currently authenticated user’s ID. - optional
	UserID *int `json:"user_id,omitempty" url:"user_id,omitempty"`

	// The ID of the project to associate with the time entry. - required
	ProjectID int `json:"project_id" url:"project_id,omitempty"`

	// The ID of the task to associate with the time entry. - required
	TaskID int `json:"task_id" url:"task_id,omitempty"`

	// The ISO 8601 formatted date the time entry was spent. - required
	SpentDate Date `json:"spent_date" url:"spent_date,omitempty"`

	// The time the entry started. Defaults to the current time.
	// Example: “8:00am”. - optional
	StartedTime *KitchenTime `json:"started_time,omitempty" url:"started_time,omitempty"`

	// The time the entry ended. If provided, is_running will be set to
	// false. If not provided, is_running will be set to true. - optional
	EndedTime *KitchenTime `json:"ended_time,omitempty" url:"ended_time,omitempty"`

	// Any notes to be associated with the time entry. - optional
	Notes string `json:"notes,omitempty" url:"notes,omitempty"`

	// An object containing the id, group_id, account_id, and permalink of
	// the external reference. - optional
	ExternalReference *ExternalReference `json:"external_reference,omitempty" url:"external_reference,omitempty"`
}

The body required to create a time entry using the start and end time. Note that this same struct and endpoint is also used to start a timer. If an EndedTime is not provided, then the timer will be running. If a StartedTime is not provided, then the start time of the timer will be the current time.

Also note that if your company settings are such that users are required to enter time as a duration rather than using start and end times, then this endpoint will only be used to start a timer, regardless of the values of StartedTime and EndedTime.

func (CreateTimeEntryBodyStartEnd) GetTimeEntryBodyParams

func (b CreateTimeEntryBodyStartEnd) GetTimeEntryBodyParams() string

func (CreateTimeEntryBodyStartEnd) IsValid

func (b CreateTimeEntryBodyStartEnd) IsValid() bool

type Date

type Date struct {
	time.Time
}

A wrapper to facilitate marshalling time.Time types into a DateOnly string for API calls, and vice versa.

func (Date) MarshalJSON

func (s Date) MarshalJSON() ([]byte, error)

func (*Date) UnmarshalJSON

func (s *Date) UnmarshalJSON(input []byte) error

type ErrorCodeResponse

type ErrorCodeResponse struct {
	StatusCode int
	Message    string
}

A struct to carry error codes from the response up to the main application

func (ErrorCodeResponse) Error

func (e ErrorCodeResponse) Error() string

type ExternalReference

type ExternalReference struct {
	ID             int    `json:"id"`
	GroupID        int    `json:"group_id"`
	AccountID      int    `json:"account_id"`
	Permalink      string `json:"permalink"`
	Service        string `json:"service"`
	ServiceIconURL string `json:"service_icon_url"`
}

Documentation is thin, but this appears to be a reference to a celandar event. I.e., this would be used to match a time entry with a GCal import.

type GetProjectAssignmentParameters

type GetProjectAssignmentParameters struct {
	// Only return project assignments that have been updated since the given
	// date and time.
	UpdatedSince time.Time `json:"updated_since" url:"updated_since,omitempty"`

	// DEPRECATED The page number to use in pagination. For instance, if
	// you make a list request and receive 2000 records, your subsequent call
	// can include page=2 to retrieve the next page of the list. (Default: 1)
	Page int `json:"page" url:"page,omitempty"`

	// The number of records to return per page. Can range between 1 and
	// 2000.  (Default: 2000)
	PerPage int `json:"per_page" url:"per_page,omitempty"`
}

type GetTimeEntryParameters

type GetTimeEntryParameters struct {
	// Only return time entries belonging to the user with the given ID.
	UserID int `json:"user_id" url:"user_id,omitempty"`

	// Only return time entries belonging to the client with the given ID.
	ClientID int `json:"client_id" url:"client_id,omitempty"`

	// Only return time entries belonging to the project with the given ID.
	ProjectID int `json:"project_id" url:"project_id,omitempty"`

	// Only return time entries belonging to the task with the given ID.
	TaskID int `json:"task_id" url:"task_id,omitempty"`

	// Only return time entries with the given external_reference ID.
	ExternalReferenceID string `json:"external_reference_id" url:"external_reference_id,omitempty"`

	// Pass true to only return time entries that have been invoiced and
	// false to return time entries that have not been invoiced.
	IsBilled bool `json:"is_billed" url:"is_billed,omitempty"`

	// Pass true to only return running time entries and false to return non-
	// running time entries.
	IsRunning bool `json:"is_running" url:"is_running,omitempty"`

	// Only return time entries that have been updated since the given date
	// and time. Use the ISO 8601 Format.
	UpdatedSince time.Time `json:"updated_since" url:"updated_since,omitempty"`

	// Only return time entries with a spent_date on or after the given date.
	From Date `json:"from" url:"from,omitempty"`

	// Only return time entries with a spent_date on or before the
	// given date.
	To Date `json:"to" url:"to,omitempty"`

	// The page number to use in pagination. For instance, if you make a list
	// request and receive 2000 records, your subsequent call can include
	// page=2 to retrieve the next page of the list. (Default: 1)
	Page int `json:"page" url:"page,omitempty"`

	// The number of records to return per page. Can range between 1 and
	// 2000. (Default: 2000)
	PerPage int `json:"per_page" url:"per_page,omitempty"`
}

type KitchenTime

type KitchenTime struct {
	time.Time
}

A wrapper to facilitate marshalling time.Time types into a KitchenTime string for API calls, and vice versa. Note that when unmarhsalling JSON, we have only the time text string, and not the date, so the date portion of the time.Time value will be unreliable.

func (KitchenTime) MarshalJSON

func (kitchenTime KitchenTime) MarshalJSON() ([]byte, error)

func (*KitchenTime) UnmarshalJSON

func (kitchenTime *KitchenTime) UnmarshalJSON(b []byte) error

type Pagination

type Pagination struct {
	PerPage      int  `json:"per_page"`
	TotalPages   int  `json:"total_pages"`
	TotalEntries int  `json:"total_entries"`
	NextPage     *int `json:"next_page"`
	PreviousPage *int `json:"previous_page"`
	Page         int  `json:"page"`
	Links        struct {
		First    string  `json:"first"`
		Next     *string `json:"next"`
		Previous *string `json:"previous"`
		Last     string  `json:"last"`
	} `json:"links"`
}

Properties included on a variety of calls to simplify pagination. Harvest uses cursor-based pagination.

type ProjectAssignment

type ProjectAssignment struct {
	// Unique ID for the project assignment.
	ID int `json:"id"`

	// Whether the project assignment is active or archived.
	IsActive bool `json:"is_active"`

	// Determines if the user has Project Manager permissions for
	// the project.
	IsProjectManager bool `json:"is_project_manager"`

	// Determines which billable rate(s) will be used on the project for this
	// user when `bill_by` is `People`. When `true`, the project will use the
	// user’s default billable rates. When `false`, the project will use the
	// custom rate defined on this user assignment.
	UseDefaultRates bool `json:"use_default_rates"`

	// Custom rate used when the project’s bill_by is People and use_default
	// rates is false.
	HourlyRate float64 `json:"hourly_rate"`

	// Budget used when the project’s budget_by is person.
	Budget float64 `json:"budget"`

	// Date and time the project assignment was created.
	CreatedAt time.Time `json:"created_at"`

	// Date and time the project assignment was last updated.
	UpdatedAt time.Time `json:"updated_at"`

	// An object containing the assigned project id, name, and code.
	Project ProjectAssignmentProject `json:"project"`

	// An object containing the project’s client id and name.
	Client ProjectAssignmentClient `json:"client"`

	// Array of task assignment objects associated with the project.
	TaskAssignments []TaskAssignment `json:"task_assignments"`
}

type ProjectAssignmentClient

type ProjectAssignmentClient struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

type ProjectAssignmentProject

type ProjectAssignmentProject struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	Code string `json:"code"`
}

type ProjectAssignmentResponse

type ProjectAssignmentResponse struct {
	ProjectAssignments []ProjectAssignment `json:"project_assignments"`
	Pagination
}

type TaskAssignment

type TaskAssignment struct {
	// Unique ID for the task assignment.
	ID int `json:"id"`

	// An object containing the id, name, and code of the associated project.
	Project TaskAssignmentProject `json:"project"`

	// An object containing the id and name of the associated task.
	Task TaskAssignmentTask `json:"task"`

	// Whether the task assignment is active or archived.
	IsActive bool `json:"is_active"`

	// Whether the task assignment is billable or not. For example: if set to
	// true, all time tracked on this project for the associated task will be
	// marked as billable.
	Billable bool `json:"billable"`

	// Rate used when the project’s bill_by is Tasks.
	HourlyRate float64 `json:"hourly_rate"`

	// Budget used when the project’s budget_by is task or task_fees.
	Budget float64 `json:"budget"`

	// Date and time the task assignment was created.
	CreatedAt time.Time `json:"created_at"`

	// Date and time the task assignment was last updated.
	UpdatedAt time.Time `json:"updated_at"`
}

type TaskAssignmentProject

type TaskAssignmentProject struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	Code string `json:"code"`
}

type TaskAssignmentTask

type TaskAssignmentTask struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

type TimeEntry

type TimeEntry struct {
	// Unique ID for the time entry. Listed as 'bigint' in documentation
	ID uint64 `json:"id"`

	// Date of the time entry.
	SpentDate Date `json:"spent_date"`

	// An object containing the id and name of the associated user.
	User struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"user"`

	// A user assignment object of the associated user.
	UserAssignment UserAssignment `json:"user_assignment"`

	// An object containing the id and name of the associated client.
	Client struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"client"`

	// An object containing the id and name of the associated project.
	Project struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"project"`

	// An object containing the id and name of the associated task.
	Task struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"task"`

	// A task assignment object of the associated task.
	TaskAssignment TaskAssignment `json:"task_assignment"`

	// An object containing the id, group_id, account_id, permalink,
	// service, and service_icon_url of the associated external reference.
	ExternalReference ExternalReference `json:"external_reference"`

	// Once the time entry has been invoiced, this field will include the
	// associated invoice’s id and number.
	Invoice struct {
		ID     int    `json:"id"`
		Number string `json:"number"`
	} `json:"invoice"`

	// Number of (decimal time) hours tracked in this time entry.
	Hours float64 `json:"hours"`

	// Number of (decimal time) hours already tracked in this time entry,
	// before the timer was last started.
	HoursWithoutTimer float64 `json:"hours_without_timer"`

	// Number of (decimal time) hours tracked in this time entry used in
	// summary reports and invoices. This value is rounded according to the
	// Time Rounding setting in your Preferences.
	RoundedHours float64 `json:"rounded_hours"`

	// Notes attached to the time entry.
	Notes string `json:"notes"`

	// Whether or not the time entry has been locked.
	IsLocked bool `json:"is_locked"`

	// Why the time entry has been locked.
	LockedReason string `json:"locked_reason"`

	// Whether or not the time entry has been approved via
	// Timesheet Approval.
	IsClosed bool `json:"is_closed"`

	// Whether or not the time entry has been marked as invoiced.
	IsBilled bool `json:"is_billed"`

	// Date and time the running timer was started (if tracking by duration).
	// Use the ISO 8601 Format. Returns null for stopped timers.
	TimerStartedAt time.Time `json:"timer_started_at"`

	// Time the time entry was started (if tracking by start/end times).
	StartedTime *KitchenTime `json:"started_time"`

	// Time the time entry was ended (if tracking by start/end times).
	EndedTime *KitchenTime `json:"ended_time"`

	// Whether or not the time entry is currently running.
	IsRunning bool `json:"is_running"`

	// Whether or not the time entry is billable.
	Billable bool `json:"billable"`

	// Whether or not the time entry counts towards the project budget.
	Budgeted bool `json:"budgeted"`

	// The billable rate for the time entry.
	BillableRate float64 `json:"billable_rate"`

	// The cost rate for the time entry.
	CostRate float64 `json:"cost_rate"`

	// Date and time the time entry was created. Use the ISO 8601 Format.
	CreatedAt time.Time `json:"created_at"`

	// Date and time the time entry was last updated. Use the ISO
	// 8601 Format.
	UpdatedAt time.Time `json:"updated_at"`
}

A time entry

type TimeEntryResponse

type TimeEntryResponse struct {
	TimeEntries []TimeEntry `json:"time_entries"`
	Pagination
}

A response object from requesting time entries

type UpdateTimeEntryBody

type UpdateTimeEntryBody struct {
	// The ID of the project to associate with the time entry.
	ProjectID *int `json:"project_id,omitempty" url:"project_id,omitempty"`

	// The ID of the task to associate with the time entry.
	TaskID *int `json:"task_id,omitempty" url:"task_id,omitempty"`

	// The ISO 8601 formatted date the time entry was spent.
	SpentDate *Date `json:"spent_date,omitempty" url:"spent_date,omitempty"`

	// The time the entry started. Defaults to the current time. Example:
	// “8:00am”.
	StartedTime *KitchenTime `json:"started_time,omitempty" url:"started_time,omitempty"`

	// The time the entry ended.
	EndedTime *KitchenTime `json:"ended_time,omitempty" url:"ended_time,omitempty"`

	// The current amount of time tracked.
	Hours *float64 `json:"hours,omitempty" url:"hours,omitempty"`

	// Any notes to be associated with the time entry.
	Notes *string `json:"notes,omitempty" url:"notes,omitempty"`

	// An object containing the id, group_id, account_id, and permalink of the
	// external reference.
	ExternalReference *ExternalReference `json:"external_reference,omitempty" url:"external_reference,omitempty"`
}

func (UpdateTimeEntryBody) GetTimeEntryBodyParams

func (b UpdateTimeEntryBody) GetTimeEntryBodyParams() string

func (UpdateTimeEntryBody) IsValid

func (b UpdateTimeEntryBody) IsValid() bool

type User

type User struct {
	// Unique ID for the user.
	ID int `json:"id"`

	// The first name of the user.
	FirstName string `json:"first_name"`

	// The last name of the user.
	LastName string `json:"last_name"`

	// The email address of the user.
	Email string `json:"email"`

	// The user’s telephone number.
	Telephone string `json:"telephone"`

	// The user’s timezone.
	Timezone string `json:"timezone"`

	// Whether the user should be automatically added to future projects.
	HasAccessToAllFutureProjects bool `json:"has_access_to_all_future_projects"`

	// Whether the user is a contractor or an employee.
	IsContractor bool `json:"is_contractor"`

	// Whether the user is active or archived.
	IsActive bool `json:"is_active"`

	// The number of hours per week this person is available to work in
	// seconds, in half hour increments. For example, if a person’s capacity
	// is 35 hours, the API will return 126000 seconds.
	WeeklyCapacity int `json:"weekly_capacity"`

	// The billable rate to use for this user when they are added to
	// a project.
	DefaultHourlyRate float64 `json:"default_hourly_rate"`

	// The cost rate to use for this user when calculating a project’s costs
	// vs billable amount.
	CostRate float64 `json:"cost_rate"`

	// Descriptive names of the business roles assigned to this person. They
	// can be used for filtering reports, and have no effect in their
	// permissions in Harvest.
	Roles []string `json:"roles"`

	//help.getharvest.com/api-v2/users-api/users/users/#access-roles) that
	// determine the user’s permissions in Harvest. Possible values:
	// `administrator`, `manager` or `member`. Users with the manager role
	// can additionally be granted one or more of these roles:
	// `project_creator`, `billable_rates_manager`,
	// `managed_projects_invoice_drafter`,
	// `managed_projects_invoice_manager`, `client_and_task_manager`,
	// `time_and_expenses_manager`, `estimates_manager`.
	AccessRoles []string `json:"access_roles"` // [Access role(s)](https:

	// The URL to the user’s avatar image.
	AvatarURL string `json:"avatar_url"`

	// Date and time the user was created.
	CreatedAt time.Time `json:"created_at"`

	// Date and time the user was last updated.
	UpdatedAt time.Time `json:"updated_at"`
}

type UserAssignment

type UserAssignment struct {
	// Unique ID for the user assignment.
	ID int `json:"id"`

	// An object containing the id, name, and code of the associated project.
	Project struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
		Code string `json:"code"`
	} `json:"project"`

	// An object containing the id and name of the associated user.
	User struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"user"`

	// Whether the user assignment is active or archived.
	IsActive bool `json:"is_active"`

	// Determines if the user has Project Manager permissions for the project.
	IsProjectManager bool `json:"is_project_manager"`

	// Determines which billable rate(s) will be used on the project for this
	// user when bill_by is People. When true, the project will use the
	// user’s default billable rates. When false, the project will use the
	// custom rate defined on this user assignment.
	UseDefaultRates bool `json:"use_default_rates"`

	// Custom rate used when the project’s bill_by is People and use_default
	// rates is false.
	HourlyRate float64 `json:"hourly_rate"`

	// Budget used when the project’s budget_by is person.
	Budget float64 `json:"budget"`

	// Date and time the user assignment was created.
	CreatedAt time.Time `json:"created_at"`

	// Date and time the user assignment was last updated.
	UpdatedAt time.Time `json:"updated_at"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL