JQuery

Using the Harvest API to Build Custom Reports

We use Harvest for time-tracking, which is simple and easy to use.


Filed under:

We use Harvest for time-tracking, which is simple and easy to use. For most users the tools on the website will be enough, but if you need to create a custom report or want to share data between Harvest and another application, you can use the Harvest API. I'm primarily a PHP guy, so using the Harvest PHP library makes it even easier. This post will demonstrate how to use this to create a custom reporting tool.

In our case, we wanted to see how many hours a given user spent on weekends over a given time period.

<?php
/**
 * @file
 * This calculates the number of hours logged on weekends during a given period.
 */
 
/**
 * Set your credentials here. You must be an admin on the Harvest account for
 * this to work properly. You may want to store this in a separate file and include
 * that file here.
 *   include('settings.php');
 */
$harvest_user = ''; // Your Harvest username, usually an email address
$harvest_pass = ''; // Your Harvest password
$harvest_account = ''; // The {myaccount} portion of your Harvest url: {myaccount}.harvestapp.com
// date_default_timezone_set('America/Los_Angeles'); // Set your timezone if it is not set in your php.ini
 
// Include the HarvestAPI class
require_once 'HarvestAPI.php';
// Register the HarvestAPI autoloader
spl_autoload_register(array('HarvestAPI', 'autoload'));
 
$harvestAPI = new HarvestAPI();
$harvestAPI->setUser($harvest_user);
$harvestAPI->setPassword($harvest_pass);
$harvestAPI->setAccount($harvest_account);

That sets up our object, now we can make calls against it like so:

<?php
$result = $harvestAPI->getUsers();
// If Harvest returns successful
if ($result->code == 200) {
  $people = $result->data;
}
?>

Since we only wanted entries that were on a weekend, I made a convenience function to help keep the resulting html a little more tidy.

/**
 * @param int from
 *   A date as recongized by strtotime for report start date.
 * @param int to
 *   A date as recongized by strtotime for report end date.
 * @param int user_id
 *   The Harvest User's id.
 * @param object
 *   The Harvest API object, with user already logged in.
 * @return array
 *   The entries that were on a weekend during the time period.
 */
function getWeekendEntriesForPeriod($from, $to, $user_id, $harvestAPI) {
  $range = new Harvest_Range(date('Ymd', strtotime($from)), date('Ymd', strtotime($to)));
 
  $activity = $harvestAPI->getUserEntries($user_id, $range);
 
  $entries = array();
  $hours_per_week = array();
 
  foreach ($activity->data as $entry) {
    // We also want to calculate the total hours spent during that week
    $week_year = date('W-o', strtotime($entry->spent_at)); // Uses ISO-8601, weeks are Monday - Sunday
 
    if (!isset($hours_per_week[$week_year])) {
      $hours_per_week[$week_year] = 0;
    }
    $hours_per_week[$week_year] += $entry->hours;
 
    // If the entry is during a weekend
    $day_of_week = date('w', strtotime($entry->spent_at));
    // 0 = Sunday, 6 = Saturday
    if ($day_of_week == 0 || $day_of_week == 6) {
      $entries[] = $entry;
    }
  }
 
  // Loop through all the entries we are going to return and set our calculated hours_per_week
  foreach ($entries as $key => $entry) {
    $week_year = date('W-o', strtotime($entry->spent_at));
    $entries[$key]->hours_per_week = $hours_per_week[$week_year];
  }
 
  return $entries;
}

Finally, I built a simple persistent GET form to make a simple interface for our report. I'm also using the HTML5 date input type with a handy jQuery popup calendar.

<html>
<head>
<title>Weekend Hours Calculator</title>
<script type="text/javascript" language="javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://cdn.jquerytools.org/1.2.6/form/jquery.tools.min.js"></script>
<script type="text/javascript" language="javascript">
$(document).ready(function() {
  $(":date").dateinput();
});
</script>
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<?php
// Display form for report
$from = isset($_GET['from']) ? $_GET['from'] : date('Y-m-d', time() - 86400);
$to = isset($_GET['to']) ? $_GET['to'] : date('Y-m-d');
 
$options = array();
foreach ($people as $person) {
  // Only show active people
  if ($person->is_active == 'true') {
    $option_html = '<option value="' . $person->id . '"';
    if (isset($_GET['user_id']) && $_GET['user_id'] == $person->id) {
      $option_html .= ' selected="selected"';
    }
    $option_html .= '>' . $person->first_name . ' ' . $person->last_name . '</option>';
    $options[] = $option_html;
  }
} ?>
<form name="report" method="GET">
<label>Search:</label> <select name="user_id">
<?php implode("\n", $options); ?>
</select> <input type="date" name="from" value="<?php echo $from; ?>" /> <input type="date" name="to" value="<?php echo $to; ?>" /> <input type="submit" value="Get Report" />
</form>
<?php
// If we are running a report
if (isset($_GET['user_id']) && isset($_GET['from']) && isset($_GET['to'])) {
  $entries = getWeekendEntriesForPeriod($_GET['from'], $_GET['to'], $_GET['user_id'], $harvestAPI);
  if (count($entries)) {
    echo '<table><tr><th>Hours</th><th>Date</th><th>Weekly Hours</th><th>Details</th>';
    $hours = 0;
 
    foreach ($entries as $entry) {
      echo '<tr><td class="right">' . $entry->hours . '</td><td>' . date('l, M j, Y', strtotime($entry->spent_at)) . '</td><td>' . $entry->hours_per_week . '</td><td>' . $entry->notes . '</td></tr>';
      $hours += $entry->hours;
    }
    echo '<tr><th class="right">' . $hours .'</th><th class="left" colspan="3">Total Weekend Hours</th></tr></table>';
  }
  //
  else {
    echo '<div class="noresults">No hours reported on a weekend for this user during the time period.</div>';
  }
}
?>
</body>
</html>

And the end result is a simple but informative table:

Similar posts

Get notified on new marketing insights

Be the first to know about new B2B SaaS Marketing insights to build or refine your marketing function with the tools and knowledge of today’s industry.