JavaScript SDK: Timesheet API

The Harvest.Timesheet class is a great way to get up and running quickly with the Harvest SDK. It provides convenience methods for dealing with timers, and checks for updates to the current user's status at regular intervals. Harvest.Timesheet wraps around the Harvest.Network library, so you can use it in conjunction with custom calls to the REST API.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>
<!-- Harvest SDK -->
<!--[if lt IE 8]>
  <script src="//api.harvestapp.com/javascripts/json2.js" type="text/javascript"></script>
<![endif]-->
<script src="//api.harvestapp.com/javascripts/sdk/sdk.js" type="text/javascript"></script>
<script type="text/javascript">
  Harvest.Session.client_id( /* Your client_id */ );

  network = new Harvest.Network( new Harvest.Session() );

  if ( network.is_authenticated() ) {

    // Create a timesheet object to watch for updates.
    //
    timesheet = new Harvest.Timesheet( network, {
      onUpdate: function(){

        // When we get fresh data on the timesheet, redraw the project list.
        //
        var projects_html = '';
        for (var project in timesheet.projects) {
          projects_html << '<li>'+project.name+'</li>';
        }
        $('#projects_list').html( 'Available projects:<br/><ul>'+projects_html+'</ul>' );

        // Also display the notes for the currently running timer.
        //
        $('#running_timer').html( 'Running timer: '+timesheet.running_entry().notes );
      }
    });

    // Watch a form for a submission event, and send
    // the data to Harvest.
    //
    $('#harvest_entry').submit(function(){
      timesheet.create_entry({
        notes: $('#harvest_entry input[name=notes]').val(),
        project_id: $('#harvest_entry input[name=project_id]').val(),
        task_id: $('#harvest_entry input[name=task_id]').val()
      });
    });

  } else {
    $('<a>Connect to Harvest</a>').attr('href', network.session.authorization_uri() ).appendTo('body');
  }
</script>
<!-- End Harvest SDK -->

The best way to use Harvest.Timesheet is to create an instance of it, but you can also call the exact same functions on Harvest.Timesheet directly if you pass a Harvest.Network object as the first argument. This documentation assumes the instance style.

Harvest.Timesheet usage
new Harvest.Timesheet( network, options={} )

Create a timesheet object. network is a Harvest.Network object and options an object accepting the following optional properties:

  • update_timeout: (default is 5000 milliseconds) - How often the SDK should check Harvest for updated information. If you set this too low, you may hit API usage limits.
  • onUpdate: function(timesheet) {} - The callback function fired on each successful timesheet update request. The timesheet itself is passed into the function. Before this function is called, the projects and entries properties will be set on the object instance.
timesheet.create_entry( entry, onComplete )

Create a time entry in Harvest. See creating an entry in the REST API for more details on how to create running timers and timers for duration. The optional onComplete callback is passed the server response, in this case the entry just created.

timesheet.create_entry({
  notes: 'Test api support',
  hours: 2,
  project_id: 3,
  task_id: 14,
  spent_at: 'Tue, 17 Oct 2006'
}, function(entry) {
  console.dir(entry);
});
timesheet.running_entry()

A convenience method for fetching the currently running entry on the day's entries.

timesheet.toggle_entry( id, onComplete )

Toggle a timer in Harvest, from running to stopped or stopped to running. See toggling a timer to learn more about the response object. Do not assume your timer is now running or stopped, instead check against the timesheet.entries.

timesheet = new Harvest.Timesheet( network, {

  // This update will fire after toggle_entry, so
  // draw the current timer every-time from the update
  // event.
  //
  onUpdate: function(my_timesheet){
    draw_timer( my_timesheet.running_timer() );
  }

});

timesheet.toggle_entry( 2, function(entry) {

  // Don't assume this entry sent back is actually
  // running.
  //
  console.dir(entry);

});