Example #1
0
 public static function SyncModifyTaskItem($arModifyEventArray)
 {
     global $DB;
     $ID = $arModifyEventArray["ID"];
     $arFields = array("RESPONSIBLE_ID" => $arModifyEventArray["USER_ID"], "SITE_ID" => SITE_ID, "EXCHANGE_ID" => $arModifyEventArray["XML_ID"], "EXCHANGE_MODIFIED" => $arModifyEventArray["MODIFICATION_LABEL"], "TITLE" => $arModifyEventArray["SUBJECT"], "DESCRIPTION" => $arModifyEventArray["BODY"], "CREATED_DATE" => $arModifyEventArray["DATE_CREATE"], "PRIORITY" => self::$PriorityMapping[strtolower($arModifyEventArray["IMPORTANCE"])], "DURATION_FACT" => ceil($arModifyEventArray["ACTUAL_WORK"] / 60), "START_DATE_PLAN" => $arModifyEventArray["START_DATE"], "DEADLINE" => $arModifyEventArray["DUE_DATE"], "STATUS" => self::$StatusMapping[strtolower($arModifyEventArray["STATUS"])], "DURATION_PLAN" => ceil($arModifyEventArray["TOTAL_WORK"] / 60), "DURATION_TYPE" => "hours");
     $arExtraFields = array();
     if (isset($arModifyEventArray['ExtendedProperty']) && is_array($arModifyEventArray['ExtendedProperty'])) {
         foreach ($arModifyEventArray['ExtendedProperty'] as $arExtendedProperty) {
             $arExtraFields[$arExtendedProperty['Name']] = $arExtendedProperty['Value'];
         }
     }
     if ($ID == 0) {
         $arFields["STATUS_CHANGED_BY"] = $arFields["CHANGED_BY"] = $arFields["CREATED_BY"] = $arFields["RESPONSIBLE_ID"];
         $arFields["STATUS_CHANGED_DATE"] = $arFields["CHANGED_DATE"] = $arFields["CREATED_DATE"];
         $ID = $DB->Add("b_tasks", $arFields, array("DESCRIPTION"), "tasks");
         if ($ID) {
             $arFields["ID"] = $ID;
             CTaskNotifications::SendAddMessage($arFields);
             $arLogFields = array("TASK_ID" => $ID, "USER_ID" => $arFields["CREATED_BY"], "CREATED_DATE" => $arFields["CREATED_DATE"], "FIELD" => "NEW");
             $log = new CTaskLog();
             $log->Add($arLogFields);
         }
     } else {
         $strUpdate = $DB->PrepareUpdate("b_tasks", $arFields, "tasks");
         $strSql = "UPDATE b_tasks SET " . $strUpdate . " WHERE ID=" . $ID;
         $arBinds = array('DESCRIPTION' => $arFields['DESCRIPTION']);
         $result = $DB->QueryBind($strSql, $arBinds, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
         if ($result) {
             $rsTask = CTasks::GetByID($ID, false);
             if ($arTask = $rsTask->Fetch()) {
                 $arFields["CHANGED_BY"] = $arFields["RESPONSIBLE_ID"];
                 $arFields["CHANGED_DATE"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), time() + CTimeZone::GetOffset());
                 CTaskNotifications::SendUpdateMessage($arFields, $arTask);
                 $arChanges = CTaskLog::GetChanges($arTask, $arFields);
                 foreach ($arChanges as $key => $value) {
                     $arLogFields = array("TASK_ID" => $ID, "USER_ID" => $arFields["CHANGED_BY"], "CREATED_DATE" => $arFields["CHANGED_DATE"], "FIELD" => $key, "FROM_VALUE" => $value["FROM_VALUE"], "TO_VALUE" => $value["TO_VALUE"]);
                     $log = new CTaskLog();
                     $log->Add($arLogFields);
                 }
             }
         }
     }
 }
 public static function SendUpdateMessage($arFields, $arTask, $bSpawnedByAgent = false, array $parameters = array())
 {
     global $USER;
     $occurAsUserId = self::getOccurAsUserId($arFields, $arTask, $bSpawnedByAgent, $parameters);
     $effectiveUserId = self::getEffectiveUserId($arFields, $arTask, $bSpawnedByAgent, $parameters);
     // generally, $occurAsUserId === $effectiveUserId, but sometimes dont
     /*
     $bSpawnedByAgent === true means that this task was "created\updated" on angent, and 
     in case of that, message author is defined as $arTask['CRAETED_BY'] (below)
     */
     if (!$bSpawnedByAgent && $parameters['THROTTLE_MESSAGES']) {
         AgentManager::checkAgentIsAlive("notificationThrottleRelease()", 300);
         ThrottleTable::submitUpdateMessage($arTask['ID'], $occurAsUserId, $arTask, $arFields);
         return;
     }
     $isBbCodeDescription = true;
     if (isset($arFields['DESCRIPTION_IN_BBCODE'])) {
         if ($arFields['DESCRIPTION_IN_BBCODE'] === 'N') {
             $isBbCodeDescription = false;
         }
     } elseif (isset($arTask['DESCRIPTION_IN_BBCODE'])) {
         if ($arTask['DESCRIPTION_IN_BBCODE'] === 'N') {
             $isBbCodeDescription = false;
         }
     }
     $taskReassignedTo = null;
     if (isset($arFields['RESPONSIBLE_ID']) && $arFields['RESPONSIBLE_ID'] > 0 && $arFields['RESPONSIBLE_ID'] != $arTask['RESPONSIBLE_ID']) {
         $taskReassignedTo = $arFields['RESPONSIBLE_ID'];
     }
     foreach (array('CREATED_BY', 'RESPONSIBLE_ID', 'ACCOMPLICES', 'AUDITORS', 'TITLE') as $field) {
         if (!isset($arFields[$field]) && isset($arTask[$field])) {
             $arFields[$field] = $arTask[$field];
         }
     }
     $cacheWasEnabled = self::enableStaticCache();
     // $arChanges contains datetimes IN SERVER TIME, NOT CLIENT
     $arChanges = CTaskLog::GetChanges($arTask, $arFields);
     $arMerged = array('ADDITIONAL_RECIPIENTS' => array());
     if (isset($arTask['CREATED_BY'])) {
         $arMerged['ADDITIONAL_RECIPIENTS'][] = $arTask['CREATED_BY'];
     }
     if (isset($arTask['RESPONSIBLE_ID'])) {
         $arMerged['ADDITIONAL_RECIPIENTS'][] = $arTask['RESPONSIBLE_ID'];
     }
     if (isset($arTask['ACCOMPLICES']) && is_array($arTask['ACCOMPLICES'])) {
         foreach ($arTask['ACCOMPLICES'] as $userId) {
             $arMerged['ADDITIONAL_RECIPIENTS'][] = $userId;
         }
     }
     if (isset($arTask['AUDITORS']) && is_array($arTask['AUDITORS'])) {
         foreach ($arTask['AUDITORS'] as $userId) {
             $arMerged['ADDITIONAL_RECIPIENTS'][] = $userId;
         }
     }
     if (isset($arFields['ADDITIONAL_RECIPIENTS'])) {
         $arFields['ADDITIONAL_RECIPIENTS'] = array_merge($arFields['ADDITIONAL_RECIPIENTS'], $arMerged['ADDITIONAL_RECIPIENTS']);
     } else {
         $arFields['ADDITIONAL_RECIPIENTS'] = $arMerged['ADDITIONAL_RECIPIENTS'];
     }
     $arUsers = CTaskNotifications::__GetUsers($arFields);
     $ignoreAuthor = isset($parameters['IGNORE_AUTHOR']) ? !!$parameters['IGNORE_AUTHOR'] : true;
     $arRecipientsIDs = array_unique(CTaskNotifications::GetRecipientsIDs($arFields, $ignoreAuthor, false, $occurAsUserId));
     if (!empty($arRecipientsIDs) && (is_object($USER) && $USER->GetID() || $arFields["CREATED_BY"])) {
         $curUserTzOffset = (int) self::getUserTimeZoneOffset();
         $arInvariantChangesStrs = array();
         $arVolatileDescriptions = array();
         $arRecipientsIDsByTimezone = array();
         $i = 0;
         foreach ($arChanges as $key => $value) {
             ++$i;
             $actionMessage = GetMessage("TASKS_MESSAGE_" . $key);
             if (strlen($actionMessage)) {
                 $changeMessage = $actionMessage;
                 $tmpStr = '';
                 switch ($key) {
                     case 'TIME_ESTIMATE':
                         $tmpStr .= self::formatTimeHHMM($value["FROM_VALUE"], true) . " -> " . self::formatTimeHHMM($value["TO_VALUE"], true);
                         break;
                     case "TITLE":
                         $tmpStr .= $value["FROM_VALUE"] . " -> " . $value["TO_VALUE"];
                         break;
                     case "RESPONSIBLE_ID":
                         $tmpStr .= CTaskNotifications::__Users2String($value["FROM_VALUE"], $arUsers, $arFields["NAME_TEMPLATE"]) . ' -> ' . CTaskNotifications::__Users2String($value["TO_VALUE"], $arUsers, $arFields["NAME_TEMPLATE"]);
                         break;
                     case "ACCOMPLICES":
                     case "AUDITORS":
                         $tmpStr .= CTaskNotifications::__Users2String(explode(",", $value["FROM_VALUE"]), $arUsers, $arFields["NAME_TEMPLATE"]) . ' -> ' . CTaskNotifications::__Users2String(explode(",", $value["TO_VALUE"]), $arUsers, $arFields["NAME_TEMPLATE"]);
                         break;
                     case "DEADLINE":
                     case "START_DATE_PLAN":
                     case "END_DATE_PLAN":
                         // $arChanges ALREADY contains server time, no need to substract user timezone again
                         $utsFromValue = $value['FROM_VALUE'];
                         // - $curUserTzOffset;
                         $utsToValue = $value['TO_VALUE'];
                         // - $curUserTzOffset;
                         // It will be replaced below to formatted string with correct dates for different timezones
                         $placeholder = '###PLACEHOLDER###' . $i . '###';
                         $tmpStr .= $placeholder;
                         // Collect recipients' timezones
                         foreach ($arRecipientsIDs as $userId) {
                             $tzOffset = (int) self::getUserTimeZoneOffset($userId);
                             if (!isset($arVolatileDescriptions[$tzOffset])) {
                                 $arVolatileDescriptions[$tzOffset] = array();
                             }
                             if (!isset($arVolatileDescriptions[$tzOffset][$placeholder])) {
                                 // Make bitrix timestamps for given user
                                 $bitrixTsFromValue = $utsFromValue + $tzOffset;
                                 $bitrixTsToValue = $utsToValue + $tzOffset;
                                 $description = '';
                                 if ($utsFromValue > 360000) {
                                     $fromValueAsString = FormatDate('^' . CDatabase::DateFormatToPHP(FORMAT_DATETIME), $bitrixTsFromValue);
                                     $description .= $fromValueAsString;
                                 }
                                 $description .= ' --> ';
                                 if ($utsToValue > 360000) {
                                     $toValueAsString = FormatDate('^' . CDatabase::DateFormatToPHP(FORMAT_DATETIME), $bitrixTsToValue);
                                     $description .= $toValueAsString;
                                 }
                                 $arVolatileDescriptions[$tzOffset][$placeholder] = $description;
                             }
                             $arRecipientsIDsByTimezone[$tzOffset][] = $userId;
                         }
                         break;
                     case "DESCRIPTION":
                         $tmpStr .= HTMLToTxt($arFields["DESCRIPTION"]);
                         break;
                     case "TAGS":
                         $tmpStr .= ($value["FROM_VALUE"] ? str_replace(",", ", ", $value["FROM_VALUE"]) . " -> " : "") . ($value["TO_VALUE"] ? str_replace(",", ", ", $value["TO_VALUE"]) : GetMessage("TASKS_MESSAGE_NO_VALUE"));
                         break;
                     case "PRIORITY":
                         $tmpStr .= GetMessage("TASKS_PRIORITY_" . $value["FROM_VALUE"]) . " -> " . GetMessage("TASKS_PRIORITY_" . $value["TO_VALUE"]);
                         break;
                     case "GROUP_ID":
                         if ($value["FROM_VALUE"] && self::checkUserCanViewGroup($effectiveUserId, $value["FROM_VALUE"])) {
                             $arGroupFrom = self::getSocNetGroup($value["FROM_VALUE"]);
                             if ($arGroupFrom) {
                                 $tmpStr .= $arGroupFrom["NAME"] . " -> ";
                             }
                         }
                         if ($value["TO_VALUE"] && self::checkUserCanViewGroup($effectiveUserId, $value["TO_VALUE"])) {
                             $arGroupTo = self::getSocNetGroup($value["TO_VALUE"]);
                             if ($arGroupTo) {
                                 $tmpStr .= $arGroupTo["NAME"];
                             }
                         } else {
                             $tmpStr .= GetMessage("TASKS_MESSAGE_NO_VALUE");
                         }
                         break;
                     case "PARENT_ID":
                         if ($value["FROM_VALUE"]) {
                             $rsTaskFrom = CTasks::GetList(array(), array("ID" => $value["FROM_VALUE"]), array('ID', 'TITLE'));
                             if ($arTaskFrom = $rsTaskFrom->GetNext()) {
                                 $tmpStr .= $arTaskFrom["TITLE"] . " -> ";
                             }
                         }
                         if ($value["TO_VALUE"]) {
                             $rsTaskTo = CTasks::GetList(array(), array("ID" => $value["TO_VALUE"]), array('ID', 'TITLE'));
                             if ($arTaskTo = $rsTaskTo->GetNext()) {
                                 $tmpStr .= $arTaskTo["TITLE"];
                             }
                         } else {
                             $tmpStr .= GetMessage("TASKS_MESSAGE_NO_VALUE");
                         }
                         break;
                     case "DEPENDS_ON":
                         $arTasksFromStr = array();
                         if ($value["FROM_VALUE"]) {
                             $rsTasksFrom = CTasks::GetList(array(), array("ID" => explode(",", $value["FROM_VALUE"])), array('ID', 'TITLE'));
                             while ($arTaskFrom = $rsTasksFrom->GetNext()) {
                                 $arTasksFromStr[] = $arTaskFrom["TITLE"];
                             }
                         }
                         $arTasksToStr = array();
                         if ($value["TO_VALUE"]) {
                             $rsTasksTo = CTasks::GetList(array(), array("ID" => explode(",", $value["TO_VALUE"])), array('ID', 'TITLE'));
                             while ($arTaskTo = $rsTasksTo->GetNext()) {
                                 $arTasksToStr[] = $arTaskTo["TITLE"];
                             }
                         }
                         $tmpStr .= ($arTasksFromStr ? implode(", ", $arTasksFromStr) . " -> " : "") . ($arTasksToStr ? implode(", ", $arTasksToStr) : GetMessage("TASKS_MESSAGE_NO_VALUE"));
                         break;
                     case "MARK":
                         $tmpStr .= (!$value["FROM_VALUE"] ? GetMessage("TASKS_MARK_NONE") : GetMessage("TASKS_MARK_" . $value["FROM_VALUE"])) . " -> " . (!$value["TO_VALUE"] ? GetMessage("TASKS_MARK_NONE") : GetMessage("TASKS_MARK_" . $value["TO_VALUE"]));
                         break;
                     case "ADD_IN_REPORT":
                         $tmpStr .= ($value["FROM_VALUE"] == "Y" ? GetMessage("TASKS_MESSAGE_IN_REPORT_YES") : GetMessage("TASKS_MESSAGE_IN_REPORT_NO")) . " -> " . ($value["TO_VALUE"] == "Y" ? GetMessage("TASKS_MESSAGE_IN_REPORT_YES") : GetMessage("TASKS_MESSAGE_IN_REPORT_NO"));
                         break;
                     case "DELETED_FILES":
                         $tmpStr .= $value["FROM_VALUE"];
                         $tmpStr .= $value["TO_VALUE"];
                         break;
                     case "NEW_FILES":
                         $tmpStr .= $value["TO_VALUE"];
                         break;
                 }
                 if ((string) $tmpStr != '') {
                     $changeMessage .= ": [COLOR=#000]" . $tmpStr . "[/COLOR]";
                 }
                 $arInvariantChangesStrs[] = $changeMessage;
             }
         }
         $recp2tz = array();
         foreach ($arRecipientsIDsByTimezone as $tz => $rcp) {
             foreach ($rcp as $uid) {
                 $recp2tz[$uid] = $tz;
             }
         }
         $invariantDescription = null;
         if (!empty($arInvariantChangesStrs)) {
             $invariantDescription = implode("\r\n", $arInvariantChangesStrs);
         }
         if ($invariantDescription !== null && !empty($arRecipientsIDs)) {
             // If there is no volatile part of descriptions, send to all recipients at once
             if (empty($arVolatileDescriptions)) {
                 $arVolatileDescriptions['some_timezone'] = array();
                 $arRecipientsIDsByTimezone['some_timezone'] = $arRecipientsIDs;
             }
             $updateMessage = self::getGenderMessage($occurAsUserId, 'TASKS_TASK_CHANGED_MESSAGE');
             $taskName = self::formatTaskName($arTask['ID'], $arTask['TITLE'], $arTask['GROUP_ID'], false);
             $instant = str_replace(array("#TASK_TITLE#"), array($taskName), $updateMessage);
             $email = str_replace(array("#TASK_TITLE#"), array(strip_tags($taskName)), $updateMessage);
             //_dump_r('Sending UPDATE from '.$occurAsUserId.' TO '.implode(':', $arRecipientsIDs));
             CTaskNotifications::sendMessageEx($arTask["ID"], $occurAsUserId, $arRecipientsIDs, array('INSTANT' => $instant, 'EMAIL' => $email, 'PUSH' => self::makePushMessage('TASKS_TASK_CHANGED_MESSAGE', $occurAsUserId, $arTask)), array('EVENT_DATA' => array('ACTION' => 'TASK_UPDATE', 'arFields' => $arFields, 'arChanges' => $arChanges), 'TASK_ASSIGNED_TO' => $taskReassignedTo, 'CALLBACK' => array('BEFORE_SEND' => function ($message) use($isBbCodeDescription, $invariantDescription, $arVolatileDescriptions, $recp2tz) {
                 $rcp = $message['TO_USER_IDS'][0];
                 $volatile = $arVolatileDescriptions[$recp2tz[$rcp]];
                 if (is_array($volatile)) {
                     $description = str_replace(array_keys($volatile), $volatile, $invariantDescription);
                 } else {
                     $description = $invariantDescription;
                 }
                 $message['MESSAGE']['INSTANT'] = str_replace(array("#TASK_EXTRA#"), array($description), $message['MESSAGE']['INSTANT']);
                 if ($isBbCodeDescription) {
                     $parser = new CTextParser();
                     $description = str_replace("\t", ' &nbsp; &nbsp;', $parser->convertText($description));
                 }
                 $message['MESSAGE']['EMAIL'] = str_replace(array("#TASK_EXTRA#"), array($description), $message['MESSAGE']['EMAIL']);
                 return $message;
             })));
         }
     }
     // sonet log
     self::SendMessageToSocNet($arFields, $bSpawnedByAgent, $arChanges, $arTask, $parameters);
     if ($cacheWasEnabled) {
         self::disableStaticCache();
     }
 }
 public static function SendUpdateMessage($arFields, $arTask, $bSpawnedByAgent = false)
 {
     global $USER;
     $isBbCodeDescription = true;
     if (isset($arFields['DESCRIPTION_IN_BBCODE'])) {
         if ($arFields['DESCRIPTION_IN_BBCODE'] === 'N') {
             $isBbCodeDescription = false;
         }
     } elseif (isset($arTask['DESCRIPTION_IN_BBCODE'])) {
         if ($arTask['DESCRIPTION_IN_BBCODE'] === 'N') {
             $isBbCodeDescription = false;
         }
     }
     $taskReassignedTo = null;
     if (isset($arFields['RESPONSIBLE_ID']) && $arFields['RESPONSIBLE_ID'] > 0 && $arFields['RESPONSIBLE_ID'] != $arTask['RESPONSIBLE_ID']) {
         $taskReassignedTo = $arFields['RESPONSIBLE_ID'];
     }
     foreach (array('CREATED_BY', 'RESPONSIBLE_ID', 'ACCOMPLICES', 'AUDITORS', 'TITLE') as $field) {
         if (!isset($arFields[$field]) && isset($arTask[$field])) {
             $arFields[$field] = $arTask[$field];
         }
     }
     $arChanges = CTaskLog::GetChanges($arTask, $arFields);
     $arMerged = array('ADDITIONAL_RECIPIENTS' => array());
     if (isset($arTask['CREATED_BY'])) {
         $arMerged['ADDITIONAL_RECIPIENTS'][] = $arTask['CREATED_BY'];
     }
     if (isset($arTask['RESPONSIBLE_ID'])) {
         $arMerged['ADDITIONAL_RECIPIENTS'][] = $arTask['RESPONSIBLE_ID'];
     }
     if (isset($arTask['ACCOMPLICES']) && is_array($arTask['ACCOMPLICES'])) {
         foreach ($arTask['ACCOMPLICES'] as $userId) {
             $arMerged['ADDITIONAL_RECIPIENTS'][] = $userId;
         }
     }
     if (isset($arTask['AUDITORS']) && is_array($arTask['AUDITORS'])) {
         foreach ($arTask['AUDITORS'] as $userId) {
             $arMerged['ADDITIONAL_RECIPIENTS'][] = $userId;
         }
     }
     if (isset($arFields['ADDITIONAL_RECIPIENTS'])) {
         $arFields['ADDITIONAL_RECIPIENTS'] = array_merge($arFields['ADDITIONAL_RECIPIENTS'], $arMerged['ADDITIONAL_RECIPIENTS']);
     } else {
         $arFields['ADDITIONAL_RECIPIENTS'] = $arMerged['ADDITIONAL_RECIPIENTS'];
     }
     $arUsers = CTaskNotifications::__GetUsers($arFields);
     $arRecipientsIDs = array_unique(CTaskNotifications::GetRecipientsIDs($arFields));
     if (!empty($arRecipientsIDs) && (is_object($USER) && $USER->GetID() || $arFields["CREATED_BY"])) {
         $curUserTzOffset = (int) CTasksTools::getTimeZoneOffset();
         $arInvariantChangesStrs = array();
         $arVolatileDescriptions = array();
         $arRecipientsIDsByTimezone = array();
         $i = 0;
         foreach ($arChanges as $key => $value) {
             ++$i;
             $actionMessage = GetMessage("TASKS_MESSAGE_" . $key);
             if (strlen($actionMessage)) {
                 $tmpStr = $actionMessage . ": [COLOR=#000]";
                 switch ($key) {
                     case 'TIME_ESTIMATE':
                         $tmpStr .= self::formatTimeHHMM($value["FROM_VALUE"], true) . " -> " . self::formatTimeHHMM($value["TO_VALUE"], true);
                         break;
                     case "TITLE":
                         $tmpStr .= $value["FROM_VALUE"] . " -> " . $value["TO_VALUE"];
                         break;
                     case "RESPONSIBLE_ID":
                         $tmpStr .= CTaskNotifications::__Users2String($value["FROM_VALUE"], $arUsers, $arFields["NAME_TEMPLATE"]) . ' -> ' . CTaskNotifications::__Users2String($value["TO_VALUE"], $arUsers, $arFields["NAME_TEMPLATE"]);
                         break;
                     case "ACCOMPLICES":
                     case "AUDITORS":
                         $tmpStr .= CTaskNotifications::__Users2String(explode(",", $value["FROM_VALUE"]), $arUsers, $arFields["NAME_TEMPLATE"]) . ' -> ' . CTaskNotifications::__Users2String(explode(",", $value["TO_VALUE"]), $arUsers, $arFields["NAME_TEMPLATE"]);
                         break;
                     case "DEADLINE":
                     case "START_DATE_PLAN":
                     case "END_DATE_PLAN":
                         // CTasks::Log() returns bitrix timestamps for dates, so adjust them to correct unix timestamps.
                         $utsFromValue = $value['FROM_VALUE'] - $curUserTzOffset;
                         $utsToValue = $value['TO_VALUE'] - $curUserTzOffset;
                         // It will be replaced below to formatted string with correct dates for different timezones
                         $placeholder = '###PLACEHOLDER###' . $i . '###';
                         $tmpStr .= $placeholder;
                         // Collect recipients' timezones
                         foreach ($arRecipientsIDs as $userId) {
                             $tzOffset = (int) CTasksTools::getTimeZoneOffset($userId);
                             if (!isset($arVolatileDescriptions[$tzOffset])) {
                                 $arVolatileDescriptions[$tzOffset] = array();
                             }
                             if (!isset($arVolatileDescriptions[$tzOffset][$placeholder])) {
                                 // Make bitrix timestamps for given user
                                 $bitrixTsFromValue = $utsFromValue + $tzOffset;
                                 $bitrixTsToValue = $utsToValue + $tzOffset;
                                 $description = '';
                                 if ($utsFromValue > 360000) {
                                     $fromValueAsString = FormatDate('^' . CDatabase::DateFormatToPHP(FORMAT_DATETIME), $bitrixTsFromValue);
                                     $description .= $fromValueAsString;
                                 }
                                 $description .= ' --> ';
                                 if ($utsToValue > 360000) {
                                     $toValueAsString = FormatDate('^' . CDatabase::DateFormatToPHP(FORMAT_DATETIME), $bitrixTsToValue);
                                     $description .= $toValueAsString;
                                 }
                                 $arVolatileDescriptions[$tzOffset][$placeholder] = $description;
                             }
                             $arRecipientsIDsByTimezone[$tzOffset][] = $userId;
                         }
                         break;
                     case "DESCRIPTION":
                         $tmpStr .= HTMLToTxt($arFields["DESCRIPTION"]);
                         break;
                     case "TAGS":
                         $tmpStr .= ($value["FROM_VALUE"] ? str_replace(",", ", ", $value["FROM_VALUE"]) . " -> " : "") . ($value["TO_VALUE"] ? str_replace(",", ", ", $value["TO_VALUE"]) : GetMessage("TASKS_MESSAGE_NO_VALUE"));
                         break;
                     case "PRIORITY":
                         $tmpStr .= GetMessage("TASKS_PRIORITY_" . $value["FROM_VALUE"]) . " -> " . GetMessage("TASKS_PRIORITY_" . $value["TO_VALUE"]);
                         break;
                     case "GROUP_ID":
                         if ($value["FROM_VALUE"] && CSocNetGroup::CanUserViewGroup($USER->GetID(), $value["FROM_VALUE"])) {
                             $arGroupFrom = CSocNetGroup::GetByID($value["FROM_VALUE"]);
                             if ($arGroupFrom) {
                                 $tmpStr .= $arGroupFrom["NAME"] . " -> ";
                             }
                         }
                         if ($value["TO_VALUE"] && CSocNetGroup::CanUserViewGroup($USER->GetID(), $value["TO_VALUE"])) {
                             $arGroupTo = CSocNetGroup::GetByID($value["TO_VALUE"]);
                             if ($arGroupTo) {
                                 $tmpStr .= $arGroupTo["NAME"];
                             }
                         } else {
                             $tmpStr .= GetMessage("TASKS_MESSAGE_NO_VALUE");
                         }
                         break;
                     case "PARENT_ID":
                         if ($value["FROM_VALUE"]) {
                             $rsTaskFrom = CTasks::GetList(array(), array("ID" => $value["FROM_VALUE"]), array('ID', 'TITLE'));
                             if ($arTaskFrom = $rsTaskFrom->GetNext()) {
                                 $tmpStr .= $arTaskFrom["TITLE"] . " -> ";
                             }
                         }
                         if ($value["TO_VALUE"]) {
                             $rsTaskTo = CTasks::GetList(array(), array("ID" => $value["TO_VALUE"]), array('ID', 'TITLE'));
                             if ($arTaskTo = $rsTaskTo->GetNext()) {
                                 $tmpStr .= $arTaskTo["TITLE"];
                             }
                         } else {
                             $tmpStr .= GetMessage("TASKS_MESSAGE_NO_VALUE");
                         }
                         break;
                     case "DEPENDS_ON":
                         $arTasksFromStr = array();
                         if ($value["FROM_VALUE"]) {
                             $rsTasksFrom = CTasks::GetList(array(), array("ID" => explode(",", $value["FROM_VALUE"])), array('ID', 'TITLE'));
                             while ($arTaskFrom = $rsTasksFrom->GetNext()) {
                                 $arTasksFromStr[] = $arTaskFrom["TITLE"];
                             }
                         }
                         $arTasksToStr = array();
                         if ($value["TO_VALUE"]) {
                             $rsTasksTo = CTasks::GetList(array(), array("ID" => explode(",", $value["TO_VALUE"])), array('ID', 'TITLE'));
                             while ($arTaskTo = $rsTasksTo->GetNext()) {
                                 $arTasksToStr[] = $arTaskTo["TITLE"];
                             }
                         }
                         $tmpStr .= ($arTasksFromStr ? implode(", ", $arTasksFromStr) . " -> " : "") . ($arTasksToStr ? implode(", ", $arTasksToStr) : GetMessage("TASKS_MESSAGE_NO_VALUE"));
                         break;
                     case "MARK":
                         $tmpStr .= (!$value["FROM_VALUE"] ? GetMessage("TASKS_MARK_NONE") : GetMessage("TASKS_MARK_" . $value["FROM_VALUE"])) . " -> " . (!$value["TO_VALUE"] ? GetMessage("TASKS_MARK_NONE") : GetMessage("TASKS_MARK_" . $value["TO_VALUE"]));
                         break;
                     case "ADD_IN_REPORT":
                         $tmpStr .= ($value["FROM_VALUE"] == "Y" ? GetMessage("TASKS_MESSAGE_IN_REPORT_YES") : GetMessage("TASKS_MESSAGE_IN_REPORT_NO")) . " -> " . ($value["TO_VALUE"] == "Y" ? GetMessage("TASKS_MESSAGE_IN_REPORT_YES") : GetMessage("TASKS_MESSAGE_IN_REPORT_NO"));
                         break;
                     case "DELETED_FILES":
                         $tmpStr .= $value["FROM_VALUE"];
                         $tmpStr .= $value["TO_VALUE"];
                         break;
                     case "NEW_FILES":
                         $tmpStr .= $value["TO_VALUE"];
                         break;
                 }
                 $tmpStr .= "[/COLOR]";
                 $arInvariantChangesStrs[] = $tmpStr;
             }
         }
         $occurAsUserId = CTasksTools::getOccurAsUserId();
         if (!$occurAsUserId) {
             $occurAsUserId = is_object($USER) && $USER->GetID() ? $USER->GetID() : $arFields["CREATED_BY"];
         }
         $invariantDescription = null;
         if (!empty($arInvariantChangesStrs)) {
             $invariantDescription = implode("\r\n", $arInvariantChangesStrs);
         }
         if ($invariantDescription !== null && !empty($arRecipientsIDs)) {
             // If there is no volatile part of descriptions, send to all recipients at once
             if (empty($arVolatileDescriptions)) {
                 $arVolatileDescriptions['some_timezone'] = array();
                 $arRecipientsIDsByTimezone['some_timezone'] = $arRecipientsIDs;
             }
             foreach ($arVolatileDescriptions as $tzOffset => $arVolatileDescriptionsData) {
                 $strDescription = $invariantDescription;
                 foreach ($arVolatileDescriptionsData as $placeholder => $strReplaceTo) {
                     $strDescription = str_replace($placeholder, $strReplaceTo, $strDescription);
                 }
                 $message = str_replace(array("#TASK_TITLE#", "#TASK_EXTRA#"), array(self::formatTaskName($arTask['ID'], $arTask['TITLE'], $arTask['GROUP_ID'], true), $strDescription), GetMessage("TASKS_TASK_CHANGED_MESSAGE"));
                 if ($isBbCodeDescription) {
                     $parser = new CTextParser();
                     $htmlDescription = str_replace("\t", ' &nbsp; &nbsp;', $parser->convertText($strDescription));
                 } else {
                     $htmlDescription = $strDescription;
                 }
                 $message_email = str_replace(array("#TASK_TITLE#", "#TASK_EXTRA#"), array(self::formatTaskName($arTask['ID'], $arTask['TITLE'], $arTask['GROUP_ID']), $htmlDescription . "\r\n" . GetMessage('TASKS_MESSAGE_LINK') . ': #PATH_TO_TASK#'), GetMessage("TASKS_TASK_CHANGED_MESSAGE"));
                 CTaskNotifications::SendMessage($occurAsUserId, $arRecipientsIDsByTimezone[$tzOffset], $message, $arTask["ID"], $message_email, array('ACTION' => 'TASK_UPDATE', 'arFields' => $arFields, 'arChanges' => $arChanges), $taskReassignedTo);
             }
         }
     }
     // sonet log
     self::SendMessageToSocNet($arFields, $bSpawnedByAgent, $arChanges, $arTask);
 }
Example #4
0
 /**
  * This method is deprecated. Use CTaskItem::update() instead.
  * @deprecated
  */
 public function Update($ID, $arFields, $arParams = array())
 {
     global $DB, $USER, $USER_FIELD_MANAGER, $CACHE_MANAGER, $APPLICATION;
     if (isset($arFields['META::EVENT_GUID'])) {
         $eventGUID = $arFields['META::EVENT_GUID'];
         unset($arFields['META::EVENT_GUID']);
     } else {
         $eventGUID = sha1(uniqid('AUTOGUID', true));
     }
     $bWasFatalError = false;
     $ID = intval($ID);
     if ($ID < 1) {
         return false;
     }
     $userID = null;
     $bCheckRightsOnFiles = false;
     // for backward compatibility
     if (is_array($arParams)) {
         if (isset($arParams['USER_ID']) && $arParams['USER_ID'] > 0) {
             $userID = (int) $arParams['USER_ID'];
         }
         if (isset($arParams['CHECK_RIGHTS_ON_FILES'])) {
             if ($arParams['CHECK_RIGHTS_ON_FILES'] === 'Y' || $arParams['CHECK_RIGHTS_ON_FILES'] === true) {
                 $bCheckRightsOnFiles = true;
             } else {
                 $bCheckRightsOnFiles = false;
             }
         }
     }
     if ($userID === null) {
         $userID = is_object($USER) ? intval($USER->GetID()) : 1;
     }
     $rsTask = CTasks::GetByID($ID, false);
     if ($arTask = $rsTask->Fetch()) {
         if ($this->CheckFields($arFields, $ID, $userID)) {
             if ($USER_FIELD_MANAGER->CheckFields("TASKS_TASK", $ID, $arFields)) {
                 unset($arFields["ID"]);
                 $arBinds = array("DESCRIPTION" => $arFields["DESCRIPTION"], "DECLINE_REASON" => $arFields["DECLINE_REASON"]);
                 $time = time() + CTasksTools::getTimeZoneOffset();
                 $arFields["CHANGED_BY"] = $userID;
                 $arFields["CHANGED_DATE"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), $time);
                 $occurAsUserId = CTasksTools::getOccurAsUserId();
                 if (!$occurAsUserId) {
                     $occurAsUserId = $arFields["CHANGED_BY"] ? $arFields["CHANGED_BY"] : 1;
                 }
                 if (!$arFields["OUTLOOK_VERSION"]) {
                     $arFields["OUTLOOK_VERSION"] = ($arTask["OUTLOOK_VERSION"] ? $arTask["OUTLOOK_VERSION"] : 1) + 1;
                 }
                 // If new status code given AND new status code != current status => than update
                 if (isset($arFields["STATUS"]) && (int) $arTask['STATUS'] !== (int) $arFields['STATUS']) {
                     $arFields["STATUS_CHANGED_BY"] = $userID;
                     $arFields["STATUS_CHANGED_DATE"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), $time);
                     if ($arFields["STATUS"] == 5 || $arFields["STATUS"] == 4) {
                         $arFields["CLOSED_BY"] = $userID;
                         $arFields["CLOSED_DATE"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), $time);
                     } else {
                         $arFields["CLOSED_BY"] = false;
                         $arFields["CLOSED_DATE"] = false;
                         if ($arFields["STATUS"] == 3) {
                             $arFields["DATE_START"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), $time);
                         }
                     }
                 }
                 if ($arFields["REPLICATE"] == "Y") {
                     $arFields["REPLICATE_PARAMS"] = serialize($arFields["REPLICATE_PARAMS"]);
                 }
                 $arTaskCopy = $arTask;
                 // this will allow transfer data by pointer for speed-up
                 foreach (GetModuleEvents('tasks', 'OnBeforeTaskUpdate', true) as $arEvent) {
                     if (ExecuteModuleEventEx($arEvent, array($ID, &$arFields, &$arTaskCopy)) === false) {
                         $errmsg = GetMessage("TASKS_UNKNOWN_UPDATE_ERROR");
                         $errno = 'ERROR_UNKNOWN_UPDATE_TASK_ERROR';
                         if ($ex = $APPLICATION->getException()) {
                             $errmsg = $ex->getString();
                             $errno = $ex->getId();
                         }
                         $this->_errors[] = array('text' => $errmsg, 'id' => $errno);
                         return false;
                     }
                 }
                 $oTaskList = CTaskCountersProcessor::getInstance();
                 $oTaskList->onBeforeTaskUpdate($ID, $arTask, $arFields);
                 $strUpdate = $DB->PrepareUpdate("b_tasks", $arFields, "tasks");
                 $strSql = "UPDATE b_tasks SET " . $strUpdate . " WHERE ID=" . $ID;
                 $result = $DB->QueryBind($strSql, $arBinds, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
                 if ($result) {
                     CTaskCountersProcessor::onAfterTaskUpdate($ID, $arTask, $arFields);
                     $arParticipants = array_merge(array($arTask['CREATED_BY'], $arTask['RESPONSIBLE_ID']), (array) $arTask['ACCOMPLICES'], (array) $arTask['AUDITORS']);
                     if (isset($arFields['CREATED_BY'])) {
                         $arParticipants[] = $arFields['CREATED_BY'];
                     }
                     if (isset($arFields['RESPONSIBLE_ID'])) {
                         $arParticipants[] = $arFields['RESPONSIBLE_ID'];
                     }
                     if (isset($arFields['ACCOMPLICES'])) {
                         $arParticipants = array_merge($arParticipants, (array) $arFields['ACCOMPLICES']);
                     }
                     if (isset($arFields['AUDITORS'])) {
                         $arParticipants = array_merge($arParticipants, (array) $arFields['AUDITORS']);
                     }
                     $arParticipants = array_unique($arParticipants);
                     // Emit pull event
                     try {
                         $arPullRecipients = array();
                         foreach ($arParticipants as $userId) {
                             $arPullRecipients[] = (int) $userId;
                         }
                         $taskGroupId = 0;
                         // no group
                         $taskGroupIdBeforeUpdate = 0;
                         // no group
                         if (isset($arTask['GROUP_ID']) && $arTask['GROUP_ID'] > 0) {
                             $taskGroupId = (int) $arTask['GROUP_ID'];
                         }
                         // if $arFields['GROUP_ID'] not given, than it means,
                         // that group not changed during this update, so
                         // we must take existing group_id (from $arTask)
                         if (!array_key_exists('GROUP_ID', $arFields)) {
                             if (isset($arTask['GROUP_ID']) && $arTask['GROUP_ID'] > 0) {
                                 $taskGroupIdBeforeUpdate = (int) $arTask['GROUP_ID'];
                             } else {
                                 $taskGroupIdBeforeUpdate = 0;
                             }
                             // no group
                         } else {
                             if ($arFields['GROUP_ID'] > 0) {
                                 $taskGroupIdBeforeUpdate = (int) $arFields['GROUP_ID'];
                             } else {
                                 $taskGroupIdBeforeUpdate = 0;
                             }
                             // no group
                         }
                         $arPullData = array('TASK_ID' => (int) $ID, 'BEFORE' => array('GROUP_ID' => $taskGroupId), 'AFTER' => array('GROUP_ID' => $taskGroupIdBeforeUpdate), 'TS' => time(), 'event_GUID' => $eventGUID);
                         self::EmitPullWithTagPrefix($arPullRecipients, 'TASKS_GENERAL_', 'task_update', $arPullData);
                         self::EmitPullWithTag($arPullRecipients, 'TASKS_TASK_' . (int) $ID, 'task_update', $arPullData);
                     } catch (Exception $e) {
                         $bWasFatalError = true;
                         $this->_errors[] = 'at line ' . $e->GetLine() . ', ' . $e->GetMessage();
                     }
                     // changes log
                     $arTmp = array('arTask' => $arTask, 'arFields' => $arFields);
                     if (isset($arFields['DURATION_PLAN']) && isset($arFields['DURATION_TYPE'])) {
                         if ($arFields['DURATION_TYPE'] === 'hours') {
                             $arTmp['arFields']['DURATION_PLAN_SECONDS'] = $arFields['DURATION_PLAN'] * 3600;
                             unset($arTmp['arFields']['DURATION_PLAN']);
                         } elseif ($arFields['DURATION_TYPE'] === 'days') {
                             $arTmp['arFields']['DURATION_PLAN_SECONDS'] = $arFields['DURATION_PLAN'] * 3600 * 24;
                             unset($arTmp['arFields']['DURATION_PLAN']);
                         }
                     }
                     if (isset($arTask['DURATION_PLAN']) && isset($arTask['DURATION_TYPE'])) {
                         if ($arTask['DURATION_TYPE'] === 'hours') {
                             $arTmp['arTask']['DURATION_PLAN_SECONDS'] = $arTask['DURATION_PLAN'] * 3600;
                             unset($arTmp['arTask']['DURATION_PLAN']);
                         } elseif ($arTask['DURATION_TYPE'] === 'days') {
                             $arTmp['arTask']['DURATION_PLAN_SECONDS'] = $arTask['DURATION_PLAN'] * 3600 * 24;
                             unset($arTmp['arTask']['DURATION_PLAN']);
                         }
                     }
                     $arChanges = CTaskLog::GetChanges($arTmp['arTask'], $arTmp['arFields']);
                     unset($arTmp);
                     foreach ($arChanges as $key => $value) {
                         $arLogFields = array("TASK_ID" => $ID, "USER_ID" => $occurAsUserId, "CREATED_DATE" => $arFields["CHANGED_DATE"], "FIELD" => $key, "FROM_VALUE" => $value["FROM_VALUE"], "TO_VALUE" => $value["TO_VALUE"]);
                         $log = new CTaskLog();
                         $log->Add($arLogFields);
                     }
                     if (isset($arFields["ACCOMPLICES"]) && isset($arChanges["ACCOMPLICES"])) {
                         CTaskMembers::DeleteByTaskID($ID, "A");
                         CTasks::AddAccomplices($ID, $arFields["ACCOMPLICES"]);
                     }
                     if (isset($arFields["AUDITORS"]) && isset($arChanges["AUDITORS"])) {
                         CTaskMembers::DeleteByTaskID($ID, "U");
                         CTasks::AddAuditors($ID, $arFields["AUDITORS"]);
                     }
                     if (isset($arFields["FILES"]) && (isset($arChanges["NEW_FILES"]) || isset($arChanges["DELETED_FILES"]))) {
                         $arNotDeleteFiles = $arFields["FILES"];
                         CTaskFiles::DeleteByTaskID($ID, $arNotDeleteFiles);
                         CTasks::AddFiles($ID, $arFields["FILES"], array('USER_ID' => $userID, 'CHECK_RIGHTS_ON_FILES' => $bCheckRightsOnFiles));
                     }
                     if (isset($arFields["TAGS"]) && isset($arChanges["TAGS"])) {
                         CTaskTags::DeleteByTaskID($ID);
                         CTasks::AddTags($ID, $arTask["CREATED_BY"], $arFields["TAGS"], $userID);
                     }
                     if (isset($arFields["DEPENDS_ON"]) && isset($arChanges["DEPENDS_ON"])) {
                         CTaskDependence::DeleteByTaskID($ID);
                         CTasks::AddPrevious($ID, $arFields["DEPENDS_ON"]);
                     }
                     $USER_FIELD_MANAGER->Update("TASKS_TASK", $ID, $arFields, $userID);
                     $notifArFields = array_merge($arFields, array('CHANGED_BY' => $occurAsUserId));
                     if (($status = intval($arFields["STATUS"])) && $status > 0 && $status < 8 && (int) $arTask['STATUS'] !== (int) $arFields['STATUS']) {
                         if ($status == 7) {
                             $arTask["DECLINE_REASON"] = $arFields["DECLINE_REASON"];
                         }
                         CTaskNotifications::SendStatusMessage($arTask, $status, $notifArFields);
                     }
                     CTaskNotifications::SendUpdateMessage($notifArFields, $arTask);
                     CTaskComments::onAfterTaskUpdate($ID, $arTask, $arFields);
                     $arFields["ID"] = $ID;
                     $arMergedFields = array_merge($arTask, $arFields);
                     CTaskSync::UpdateItem($arFields, $arTask);
                     // MS Exchange
                     $arFields['META:PREV_FIELDS'] = $arTask;
                     try {
                         $lastEventName = '';
                         foreach (GetModuleEvents('tasks', 'OnTaskUpdate', true) as $arEvent) {
                             $lastEventName = $arEvent['TO_CLASS'] . '::' . $arEvent['TO_METHOD'] . '()';
                             ExecuteModuleEventEx($arEvent, array($ID, &$arFields, &$arTaskCopy));
                         }
                     } catch (Exception $e) {
                         CTaskAssert::logWarning('[0xee8999a8] exception in module event: ' . $lastEventName . '; at file: ' . $e->getFile() . ':' . $e->getLine() . ";\n");
                     }
                     unset($arFields['META:PREV_FIELDS']);
                     CTasks::Index($arMergedFields, $arFields["TAGS"]);
                     // search index
                     // clear cache
                     if ($arTask["GROUP_ID"]) {
                         $CACHE_MANAGER->ClearByTag("tasks_group_" . $arTask["GROUP_ID"]);
                     }
                     if ($arFields['GROUP_ID'] && $arFields['GROUP_ID'] != $arTask['GROUP_ID']) {
                         $CACHE_MANAGER->ClearByTag('tasks_group_' . $arFields['GROUP_ID']);
                     }
                     foreach ($arParticipants as $userId) {
                         $CACHE_MANAGER->ClearByTag("tasks_user_" . $userId);
                     }
                     if ($bWasFatalError) {
                         soundex('push&pull: bWasFatalError === true');
                     }
                     return true;
                 }
             } else {
                 $e = $APPLICATION->GetException();
                 foreach ($e->messages as $msg) {
                     $this->_errors[] = $msg;
                 }
             }
         }
     }
     if (sizeof($this->_errors) == 0) {
         $this->_errors[] = array("text" => GetMessage("TASKS_UNKNOWN_UPDATE_ERROR"), "id" => "ERROR_UNKNOWN_UPDATE_TASK_ERROR");
     }
     return false;
 }
Example #5
0
 /**
  * This method is deprecated. Use CTaskItem::update() instead.
  * @deprecated
  */
 public function Update($ID, $arFields, $arParams = array('CORRECT_DATE_PLAN_DEPENDENT_TASKS' => true, 'CORRECT_DATE_PLAN' => true, 'THROTTLE_MESSAGES' => false))
 {
     global $DB, $USER, $USER_FIELD_MANAGER, $APPLICATION;
     if (!isset($arParams['CORRECT_DATE_PLAN'])) {
         $arParams['CORRECT_DATE_PLAN'] = true;
     }
     if (!isset($arParams['CORRECT_DATE_PLAN_DEPENDENT_TASKS'])) {
         $arParams['CORRECT_DATE_PLAN_DEPENDENT_TASKS'] = true;
     }
     if (!isset($arParams['THROTTLE_MESSAGES'])) {
         $arParams['THROTTLE_MESSAGES'] = false;
     }
     $this->lastOperationResultData = array();
     if (isset($arFields['META::EVENT_GUID'])) {
         $eventGUID = $arFields['META::EVENT_GUID'];
         unset($arFields['META::EVENT_GUID']);
     } else {
         $eventGUID = sha1(uniqid('AUTOGUID', true));
     }
     $bWasFatalError = false;
     $ID = intval($ID);
     if ($ID < 1) {
         return false;
     }
     $userID = null;
     $bCheckRightsOnFiles = false;
     // for backward compatibility
     if (!is_array($arParams)) {
         $arParams = array();
     }
     if (isset($arParams['USER_ID']) && $arParams['USER_ID'] > 0) {
         $userID = (int) $arParams['USER_ID'];
     }
     if (isset($arParams['CHECK_RIGHTS_ON_FILES'])) {
         if ($arParams['CHECK_RIGHTS_ON_FILES'] === 'Y' || $arParams['CHECK_RIGHTS_ON_FILES'] === true) {
             $bCheckRightsOnFiles = true;
         } else {
             $bCheckRightsOnFiles = false;
         }
     }
     if (!isset($arParams['CORRECT_DATE_PLAN_DEPENDENT_TASKS'])) {
         $arParams['CORRECT_DATE_PLAN_DEPENDENT_TASKS'] = true;
     }
     if (!isset($arParams['CORRECT_DATE_PLAN'])) {
         $arParams['CORRECT_DATE_PLAN'] = true;
     }
     if ($userID === null) {
         $userID = is_object($USER) ? intval($USER->GetID()) : 1;
     }
     $rsTask = CTasks::GetByID($ID, false);
     if ($arTask = $rsTask->Fetch()) {
         // check if there are userfields in $arFields
         $hasUfs = false;
         foreach ($arFields as $fld => $value) {
             $fld = trim($fld);
             if (strpos($fld, 'UF_') == 0) {
                 $hasUfs = true;
                 break;
             }
         }
         if ($this->CheckFields($arFields, $ID, $userID)) {
             $okay = $hasUfs ? $USER_FIELD_MANAGER->CheckFields("TASKS_TASK", $ID, $arFields) : true;
             if ($okay) {
                 $scheduler = null;
                 unset($arFields["ID"]);
                 $arBinds = array("DESCRIPTION" => $arFields["DESCRIPTION"], "DECLINE_REASON" => $arFields["DECLINE_REASON"]);
                 $time = time() + CTasksTools::getTimeZoneOffset();
                 $arFields["CHANGED_BY"] = $userID;
                 $arFields["CHANGED_DATE"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), $time);
                 $occurAsUserId = CTasksTools::getOccurAsUserId();
                 if (!$occurAsUserId) {
                     $occurAsUserId = $arFields["CHANGED_BY"] ? $arFields["CHANGED_BY"] : 1;
                 }
                 if (!$arFields["OUTLOOK_VERSION"]) {
                     $arFields["OUTLOOK_VERSION"] = ($arTask["OUTLOOK_VERSION"] ? $arTask["OUTLOOK_VERSION"] : 1) + 1;
                 }
                 // If new status code given AND new status code != current status => than update
                 if (isset($arFields["STATUS"]) && (int) $arTask['STATUS'] !== (int) $arFields['STATUS']) {
                     $arFields["STATUS_CHANGED_BY"] = $userID;
                     $arFields["STATUS_CHANGED_DATE"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), $time);
                     if ($arFields["STATUS"] == 5 || $arFields["STATUS"] == 4) {
                         $arFields["CLOSED_BY"] = $userID;
                         $arFields["CLOSED_DATE"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), $time);
                     } else {
                         $arFields["CLOSED_BY"] = false;
                         $arFields["CLOSED_DATE"] = false;
                         if ($arFields["STATUS"] == 3) {
                             $arFields["DATE_START"] = date($DB->DateFormatToPHP(CSite::GetDateFormat("FULL")), $time);
                         }
                     }
                 }
                 if ($arFields["REPLICATE"] == "Y") {
                     $arFields["REPLICATE_PARAMS"] = serialize($arFields["REPLICATE_PARAMS"]);
                 }
                 // when updating end or start date plan, we need to be sure the time is correct
                 if ((string) $arFields['START_DATE_PLAN'] != '' || (string) $arFields['END_DATE_PLAN'] != '') {
                     if ($arParams['CORRECT_DATE_PLAN']) {
                         /*
                         print_r('Try to update '.$ID.' to:'.PHP_EOL);
                         print_r($arFields['START_DATE_PLAN']->getInfoGmt().PHP_EOL);
                         print_r($arFields['END_DATE_PLAN']->getInfoGmt().PHP_EOL);
                         */
                         $arTaskDPCopy = $arTask;
                         if ((string) $arFields['START_DATE_PLAN'] == '') {
                             // start date will be dropped, scheduler should be informed about that
                             $arTaskDPCopy['START_DATE_PLAN'] = '';
                         }
                         if ((string) $arFields['END_DATE_PLAN'] == '') {
                             // end date will be dropped, scheduler should be informed about that
                             $arTaskDPCopy['END_DATE_PLAN'] = '';
                         }
                         $scheduler = new Scheduler($userID, $ID, $arTaskDPCopy);
                         $data = $scheduler->reScheduleTask($arFields);
                         /*
                         print_r('Actual moving '.$ID.' to:'.PHP_EOL);
                         print_r($data['START_DATE_PLAN']->getInfoGmt().PHP_EOL);
                         print_r($data['END_DATE_PLAN']->getInfoGmt().PHP_EOL);
                         */
                         // to database:
                         if ($data['START_DATE_PLAN']) {
                             if ($data['START_DATE_PLAN']->toString() != (string) $arTask['CREATED_DATE']) {
                                 $arFields['START_DATE_PLAN'] = $data['START_DATE_PLAN']->toString();
                             }
                             $data['START_DATE_PLAN_STRUCT'] = $data['START_DATE_PLAN']->getTimeStruct();
                             $data['START_DATE_PLAN'] = $data['START_DATE_PLAN']->toString();
                         }
                         if ($data['END_DATE_PLAN']) {
                             $arFields['END_DATE_PLAN'] = $data['END_DATE_PLAN']->toString();
                             $data['END_DATE_PLAN_STRUCT'] = $data['END_DATE_PLAN']->getTimeStruct();
                             $data['END_DATE_PLAN'] = $data['END_DATE_PLAN']->toString();
                         }
                         if (isset($data['DURATION_PLAN_SECONDS'])) {
                             $arFields['DURATION_PLAN_SECONDS'] = $data['DURATION_PLAN_SECONDS'];
                         }
                         unset($data['ID']);
                         unset($data['MATCH_WORK_TIME']);
                         $this->lastOperationResultData['SHIFT_RESULT'][$ID] = $data;
                     }
                 }
                 // END_DATE_PLAN will be dropped
                 if (isset($arFields['END_DATE_PLAN']) && (string) $arFields['END_DATE_PLAN'] == '') {
                     // duration is no longer adequate
                     $arFields['DURATION_PLAN'] = 0;
                 }
                 self::processDurationPlanFields($arFields, (string) $arFields['DURATION_TYPE'] != '' ? $arFields['DURATION_TYPE'] : $arTask['DURATION_TYPE']);
                 $arTaskCopy = $arTask;
                 // this will allow transfer data by pointer for speed-up
                 foreach (GetModuleEvents('tasks', 'OnBeforeTaskUpdate', true) as $arEvent) {
                     if (ExecuteModuleEventEx($arEvent, array($ID, &$arFields, &$arTaskCopy)) === false) {
                         $errmsg = GetMessage("TASKS_UNKNOWN_UPDATE_ERROR");
                         $errno = 'ERROR_UNKNOWN_UPDATE_TASK_ERROR';
                         if ($ex = $APPLICATION->getException()) {
                             $errmsg = $ex->getString();
                             $errno = $ex->getId();
                         }
                         $this->_errors[] = array('text' => $errmsg, 'id' => $errno);
                         return false;
                     }
                 }
                 $oTaskList = CTaskCountersProcessor::getInstance();
                 $oTaskList->onBeforeTaskUpdate($ID, $arTask, $arFields);
                 $strUpdate = $DB->PrepareUpdate("b_tasks", $arFields, "tasks");
                 $strSql = "UPDATE b_tasks SET " . $strUpdate . " WHERE ID=" . $ID;
                 $result = $DB->QueryBind($strSql, $arBinds, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
                 if ($result) {
                     CTaskCountersProcessor::onAfterTaskUpdate($ID, $arTask, $arFields);
                     $arParticipants = array_merge(array($arTask['CREATED_BY'], $arTask['RESPONSIBLE_ID']), (array) $arTask['ACCOMPLICES'], (array) $arTask['AUDITORS']);
                     if (isset($arFields['CREATED_BY'])) {
                         $arParticipants[] = $arFields['CREATED_BY'];
                     }
                     if (isset($arFields['RESPONSIBLE_ID'])) {
                         $arParticipants[] = $arFields['RESPONSIBLE_ID'];
                     }
                     if (isset($arFields['ACCOMPLICES'])) {
                         $arParticipants = array_merge($arParticipants, (array) $arFields['ACCOMPLICES']);
                     }
                     if (isset($arFields['AUDITORS'])) {
                         $arParticipants = array_merge($arParticipants, (array) $arFields['AUDITORS']);
                     }
                     $arParticipants = array_unique($arParticipants);
                     // Emit pull event
                     try {
                         $arPullRecipients = array();
                         foreach ($arParticipants as $userId) {
                             $arPullRecipients[] = (int) $userId;
                         }
                         $taskGroupId = 0;
                         // no group
                         $taskGroupIdBeforeUpdate = 0;
                         // no group
                         if (isset($arTask['GROUP_ID']) && $arTask['GROUP_ID'] > 0) {
                             $taskGroupId = (int) $arTask['GROUP_ID'];
                         }
                         // if $arFields['GROUP_ID'] not given, than it means,
                         // that group not changed during this update, so
                         // we must take existing group_id (from $arTask)
                         if (!array_key_exists('GROUP_ID', $arFields)) {
                             if (isset($arTask['GROUP_ID']) && $arTask['GROUP_ID'] > 0) {
                                 $taskGroupIdBeforeUpdate = (int) $arTask['GROUP_ID'];
                             } else {
                                 $taskGroupIdBeforeUpdate = 0;
                             }
                             // no group
                         } else {
                             if ($arFields['GROUP_ID'] > 0) {
                                 $taskGroupIdBeforeUpdate = (int) $arFields['GROUP_ID'];
                             } else {
                                 $taskGroupIdBeforeUpdate = 0;
                             }
                             // no group
                         }
                         $arPullData = array('TASK_ID' => (int) $ID, 'BEFORE' => array('GROUP_ID' => $taskGroupId), 'AFTER' => array('GROUP_ID' => $taskGroupIdBeforeUpdate), 'TS' => time(), 'event_GUID' => $eventGUID);
                         self::EmitPullWithTagPrefix($arPullRecipients, 'TASKS_GENERAL_', 'task_update', $arPullData);
                         self::EmitPullWithTag($arPullRecipients, 'TASKS_TASK_' . (int) $ID, 'task_update', $arPullData);
                     } catch (Exception $e) {
                         $bWasFatalError = true;
                         $this->_errors[] = 'at line ' . $e->GetLine() . ', ' . $e->GetMessage();
                     }
                     // changes log
                     $arTmp = array('arTask' => $arTask, 'arFields' => $arFields);
                     if (isset($arTask['DURATION_PLAN'])) {
                         $arTmp['arTask']['DURATION_PLAN_SECONDS'] = $arTask['DURATION_PLAN_SECONDS'];
                         unset($arTmp['arTask']['DURATION_PLAN']);
                     }
                     if (isset($arFields['DURATION_PLAN'])) {
                         // at this point, $arFields['DURATION_PLAN'] in seconds
                         $arTmp['arFields']['DURATION_PLAN_SECONDS'] = $arFields['DURATION_PLAN'];
                         unset($arTmp['arFields']['DURATION_PLAN']);
                     }
                     $arChanges = CTaskLog::GetChanges($arTmp['arTask'], $arTmp['arFields']);
                     unset($arTmp);
                     foreach ($arChanges as $key => $value) {
                         $arLogFields = array("TASK_ID" => $ID, "USER_ID" => $occurAsUserId, "CREATED_DATE" => $arFields["CHANGED_DATE"], "FIELD" => $key, "FROM_VALUE" => $value["FROM_VALUE"], "TO_VALUE" => $value["TO_VALUE"]);
                         $log = new CTaskLog();
                         $log->Add($arLogFields);
                     }
                     if (isset($arFields["ACCOMPLICES"]) && isset($arChanges["ACCOMPLICES"])) {
                         CTaskMembers::DeleteByTaskID($ID, "A");
                         CTasks::AddAccomplices($ID, $arFields["ACCOMPLICES"]);
                     }
                     if (isset($arFields["AUDITORS"]) && isset($arChanges["AUDITORS"])) {
                         CTaskMembers::DeleteByTaskID($ID, "U");
                         CTasks::AddAuditors($ID, $arFields["AUDITORS"]);
                     }
                     if (isset($arFields["FILES"]) && (isset($arChanges["NEW_FILES"]) || isset($arChanges["DELETED_FILES"]))) {
                         $arNotDeleteFiles = $arFields["FILES"];
                         CTaskFiles::DeleteByTaskID($ID, $arNotDeleteFiles);
                         CTasks::AddFiles($ID, $arFields["FILES"], array('USER_ID' => $userID, 'CHECK_RIGHTS_ON_FILES' => $bCheckRightsOnFiles));
                     }
                     if (isset($arFields["TAGS"]) && isset($arChanges["TAGS"])) {
                         CTaskTags::DeleteByTaskID($ID);
                         CTasks::AddTags($ID, $arTask["CREATED_BY"], $arFields["TAGS"], $userID);
                     }
                     if (isset($arFields["DEPENDS_ON"]) && isset($arChanges["DEPENDS_ON"])) {
                         CTaskDependence::DeleteByTaskID($ID);
                         CTasks::AddPrevious($ID, $arFields["DEPENDS_ON"]);
                     }
                     if ($hasUfs) {
                         $USER_FIELD_MANAGER->Update("TASKS_TASK", $ID, $arFields, $userID);
                     }
                     // tasks dependence
                     if ($arParams['CORRECT_DATE_PLAN'] && $arParams['CORRECT_DATE_PLAN_DEPENDENT_TASKS'] && (isset($arFields["START_DATE_PLAN"]) || isset($arFields["END_DATE_PLAN"]))) {
                         if ($scheduler === null) {
                             $scheduler = new Scheduler($userID, $ID, $arTask);
                         }
                         $relatedTaskUpdate = $scheduler->reScheduleRelatedTasks();
                         if (is_array($relatedTaskUpdate)) {
                             $relatedUpdateParams = $arParams;
                             $relatedUpdateParams['CORRECT_DATE_PLAN'] = false;
                             // no self-correction
                             $relatedUpdateParams['CORRECT_DATE_PLAN_DEPENDENT_TASKS'] = false;
                             // no sub-correction
                             foreach ($relatedTaskUpdate as $relatedTaskId => $relatedTaskData) {
                                 $relatedTaskData['START_DATE_PLAN_STRUCT'] = $relatedTaskData['START_DATE_PLAN']->getTimeStruct();
                                 // as struct
                                 $relatedTaskData['END_DATE_PLAN_STRUCT'] = $relatedTaskData['END_DATE_PLAN']->getTimeStruct();
                                 // as struct
                                 $relatedTaskData['START_DATE_PLAN'] = $relatedTaskData['START_DATE_PLAN']->toString();
                                 // as string, not object
                                 $relatedTaskData['END_DATE_PLAN'] = $relatedTaskData['END_DATE_PLAN']->toString();
                                 // as string, not object
                                 $relatedTask = new CTasks();
                                 $relatedTask->update($relatedTaskId, $relatedTaskData, $relatedUpdateParams);
                                 $this->lastOperationResultData['SHIFT_RESULT'][$relatedTaskId] = $relatedTaskData;
                             }
                         }
                     }
                     $notifArFields = array_merge($arFields, array('CHANGED_BY' => $occurAsUserId));
                     if (($status = intval($arFields["STATUS"])) && $status > 0 && $status < 8 && (int) $arTask['STATUS'] !== (int) $arFields['STATUS']) {
                         if ($status == 7) {
                             $arTask["DECLINE_REASON"] = $arFields["DECLINE_REASON"];
                         }
                         CTaskNotifications::SendStatusMessage($arTask, $status, $notifArFields);
                     }
                     CTaskNotifications::SendUpdateMessage($notifArFields, $arTask, false, $arParams);
                     CTaskComments::onAfterTaskUpdate($ID, $arTask, $arFields);
                     $arFields["ID"] = $ID;
                     $arMergedFields = array_merge($arTask, $arFields);
                     CTaskSync::UpdateItem($arFields, $arTask);
                     // MS Exchange
                     $arFields['META:PREV_FIELDS'] = $arTask;
                     try {
                         $lastEventName = '';
                         foreach (GetModuleEvents('tasks', 'OnTaskUpdate', true) as $arEvent) {
                             $lastEventName = $arEvent['TO_CLASS'] . '::' . $arEvent['TO_METHOD'] . '()';
                             ExecuteModuleEventEx($arEvent, array($ID, &$arFields, &$arTaskCopy));
                         }
                     } catch (Exception $e) {
                         CTaskAssert::logWarning('[0xee8999a8] exception in module event: ' . $lastEventName . '; at file: ' . $e->getFile() . ':' . $e->getLine() . ";\n");
                     }
                     unset($arFields['META:PREV_FIELDS']);
                     // clear cache
                     static::addCacheIdToClear("tasks_" . $ID);
                     if ($arTask["GROUP_ID"]) {
                         static::addCacheIdToClear("tasks_group_" . $arTask["GROUP_ID"]);
                     }
                     if ($arFields['GROUP_ID'] && $arFields['GROUP_ID'] != $arTask['GROUP_ID']) {
                         static::addCacheIdToClear("tasks_group_" . $arFields["GROUP_ID"]);
                     }
                     foreach ($arParticipants as $userId) {
                         static::addCacheIdToClear("tasks_user_" . $userId);
                     }
                     static::clearCache();
                     if ($bWasFatalError) {
                         soundex('push&pull: bWasFatalError === true');
                     }
                     $this->previousData = $arTask;
                     return true;
                 }
             } else {
                 $e = $APPLICATION->GetException();
                 foreach ($e->messages as $msg) {
                     $this->_errors[] = $msg;
                 }
             }
         }
     }
     if (sizeof($this->_errors) == 0) {
         $this->_errors[] = array("text" => GetMessage("TASKS_UNKNOWN_UPDATE_ERROR"), "id" => "ERROR_UNKNOWN_UPDATE_TASK_ERROR");
     }
     return false;
 }