/** * update an entry * * <code> * $entry = new DayEntry(); * $entry->set("id" 11111); * $entry->set("notes", "Test Support"); * $entry->set("hours", 3); * $entry->set("project_id", 3); * $entry->set("task_id", 14); * $entry->set("spent_at", "Tue, 17 Oct 2006"); * * $api = new HarvestApi(); * * $result = $api->try($entry); * if ($result->isSuccess()) { * // success logic * } * </code> * * @param DayEntry $entry * @param bool $other_user * @return Result * * @see http://www.getharvest.com/api/time-tracking#other-users */ public function updateEntry(DayEntry $entry, $other_user = true) { $url = "daily/update/{$entry->id}"; if ($other_user) { $url .= "?of_user="******"user-id"); } return $this->performPost($url, $entry->toXML()); }
/** * Sync a single harvest time entry. * * @param \Harvest\Model\DayEntry $harvest_entry * * @return bool */ protected function syncEntry(DayEntry $harvest_entry) { // Check spelling. $words = explode(' ', preg_replace('/[^a-z]+/i', ' ', $harvest_entry->get('notes'))); $spelling_errors = array(); foreach ($words as $word) { if (!pspell_check($this->pspellLink, $word)) { $spelling_errors[] = $word; } } if ($spelling_errors) { $this->userTimeEntryErrors[$harvest_entry->get('user-id')]['spelling'][] = ['entry' => $harvest_entry, 'spelling-errors' => $spelling_errors]; } $redmine_issue = $this->getRedmineIssue($harvest_entry); if (!$redmine_issue) { return false; } $existing_redmine_time_entries = $this->getExistingRedmineIssueTimeEntries($redmine_issue, $harvest_entry); // If there are existing Redmine time entries matching this harvest entry and we are not updating, skip. if (count($existing_redmine_time_entries) > 0 && !$this->input->getOption('update')) { return false; } // Or if there is more than one matching redmine time entry, throw an error and continue. if (count($existing_redmine_time_entries) > 1) { $this->output->writeln(sprintf('<error>Multiple Redmine time entries matching harvest time entry %d. See entries %s</error>', $harvest_entry->get('id'), json_encode($existing_redmine_time_entries))); $this->errors = true; return false; } // If Harvest user is not mapped to a redmine user, throw an error and continue. if (!isset($this->userMap[$harvest_entry->get('user-id')])) { $this->output->writeln(sprintf('<error>No mapping is defined for user %d</error>', $harvest_entry->get('user-id'))); $this->errors = true; return false; } // Log the entry. $redmine_entry_params = $this->populateRedmineTimeEntry($redmine_issue, $harvest_entry); // Check rounding. if ($redmine_entry_params['hours'] != $harvest_entry->get('hours')) { $this->userTimeEntryErrors[$harvest_entry->get('user-id')]['rounding'][] = ['entry' => $harvest_entry, 'rounded-hours' => $redmine_entry_params['hours']]; } $save_entry_result = false; $this->setRedmineClient(); if (!$this->input->getOption('dry-run')) { try { $this->redmineClient->setImpersonateUser($this->userMap[$harvest_entry->get('user-id')]); $save_entry_result = $this->saveHarvestTimeEntryToRedmine($redmine_entry_params, $existing_redmine_time_entries); } catch (\Exception $e) { $this->output->writeln(sprintf('<error>Failed to create time entry for redmine issue #%d, harvest id %d, exception %s</error>', $redmine_issue['issue']['id'], $harvest_entry->get('id'), $e->getMessage())); } finally { $this->redmineClient->setImpersonateUser(null); } } if ($save_entry_result || $this->input->getOption('dry-run')) { $this->output->writeln(sprintf('<comment>%s time entry for issue #%d with %s hours (Harvest hours: %s)</comment>', count($existing_redmine_time_entries) > 0 ? 'Updated' : 'Created', $redmine_issue['issue']['id'], $redmine_entry_params['hours'], $harvest_entry->get('hours'))); } return $save_entry_result; }