/**
  * Hook performing actual save
  *
  * @param string $newCode
  * @param int $userId
  * @return $changed
  */
 public function setReceptionCode($newCode, $userId)
 {
     $oldCode = $this->respondentTrack->getReceptionCode()->getCode();
     // Use the repesondent track function as that cascades the consent code
     $changed = $this->respondentTrack->setReceptionCode($newCode, $this->formData['gr2t_comment'], $userId);
     if ($this->unDelete) {
         $this->addMessage($this->_('Track restored.'));
         if (isset($this->formData['restore_tokens']) && $this->formData['restore_tokens']) {
             $count = 0;
             foreach ($this->respondentTrack->getTokens() as $token) {
                 if ($token instanceof \Gems_Tracker_Token) {
                     if ($oldCode === $token->getReceptionCode()->getCode()) {
                         $count += $token->setReceptionCode($newCode, null, $userId);
                     }
                 }
             }
             $this->addMessage(sprintf($this->plural('%d token reception codes restored.', '%d tokens reception codes restored.', $count), $count));
         }
     } else {
         if ($this->util->getReceptionCode($newCode)->isStopCode()) {
             $this->addMessage($this->_('Track stopped.'));
         } else {
             $this->addMessage($this->_('Track deleted.'));
         }
     }
     return $changed;
 }
 /**
  * Check the valid from and until dates in the track starting at a specified token
  *
  * @param \Gems_Tracker_RespondentTrack $respTrack The respondent track to check
  * @param \Gems_Tracker_Token $startToken The token to start at
  * @param int $userId Id of the user who takes the action (for logging)
  * @param \Gems_Tracker_Token $skipToken Optional token to skip in the recalculation
  * @return int The number of tokens changed by this code
  */
 public function checkTokensFrom(\Gems_Tracker_RespondentTrack $respTrack, \Gems_Tracker_Token $startToken, $userId, \Gems_Tracker_Token $skipToken = null)
 {
     // Make sure the rounds are loaded
     $this->_ensureRounds();
     // Make sure the tokens are loaded and linked.
     $respTrack->getTokens();
     // Go
     $changed = 0;
     $token = $startToken;
     while ($token) {
         // \MUtil_Echo::track($token->getTokenId());
         // Change only not-completed tokens with a positive successcode where at least one date
         // is not set by user input
         if ($token->hasSuccesCode() && !$token->isCompleted() && !($token->isValidFromManual() && $token->isValidUntilManual()) && $token !== $skipToken) {
             //Only process the token when linked to a round
             if (array_key_exists($token->getRoundId(), $this->_rounds)) {
                 $round = $this->_rounds[$token->getRoundId()];
                 if ($token->isValidFromManual()) {
                     $validFrom = $token->getValidFrom();
                 } else {
                     $fromDate = $this->getValidFromDate($round['gro_valid_after_source'], $round['gro_valid_after_field'], $round['gro_valid_after_id'], $token, $respTrack);
                     $validFrom = $this->calculateFromDate($fromDate, $round['gro_valid_after_unit'], $round['gro_valid_after_length']);
                 }
                 // \MUtil_Echo::track($round, (string) $fromDate, $validFrom);
                 if ($token->isValidUntilManual()) {
                     $validUntil = $token->getValidUntil();
                 } else {
                     $untilDate = $this->getValidUntilDate($round['gro_valid_for_source'], $round['gro_valid_for_field'], $round['gro_valid_for_id'], $token, $respTrack, $validFrom);
                     $validUntil = $this->calculateUntilDate($untilDate, $round['gro_valid_for_unit'], $round['gro_valid_for_length']);
                 }
                 $changed += $token->setValidFrom($validFrom, $validUntil, $userId);
             }
         }
         $token = $token->getNextToken();
     }
     return $changed;
 }