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: