Current Path : /var/www/axolotl/data/www/kirov.axolotls.ru/bitrix/modules/tasks/lib/kanban/ |
Current File : /var/www/axolotl/data/www/kirov.axolotls.ru/bitrix/modules/tasks/lib/kanban/stages.php |
<?php namespace Bitrix\Tasks\Kanban; use Bitrix\Main\Entity; use Bitrix\Main\Localization\Loc; use Bitrix\Tasks\Internals\Task\SortingTable; use Bitrix\Tasks\Internals\TaskTable as Task; use Bitrix\Tasks\MemberTable; use Bitrix\Tasks\ProjectsTable; use Bitrix\Main\ORM\Fields\ArrayField; Loc::loadMessages(__FILE__); class StagesTable extends Entity\DataManager { const MY_PLAN_VERSION = '6'; /** * System type of stages (new, in progress, etc.). * Separated from other stages - timeline's stages, sprint's stages. * @see TimeLineTable::getStages() * @see SprintTable::getStages() */ const SYS_TYPE_NEW = 'NEW'; const SYS_TYPE_PROGRESS = 'WORK'; const SYS_TYPE_FINISH = 'FINISH'; const SYS_TYPE_DEFAULT = 'NEW'; const SYS_TYPE_TL1 = 'PERIOD1'; const SYS_TYPE_TL2 = 'PERIOD2'; const SYS_TYPE_TL3 = 'PERIOD3'; const SYS_TYPE_TL4 = 'PERIOD4'; const SYS_TYPE_TL5 = 'PERIOD5'; /** * Default colors. */ const DEF_COLOR_STAGE = '47D1E2'; /** * Disable pin for this users. * @var array */ private static $disablePin = array(); /** * Disable linked for this users. * @var array */ private static $disableLink = array(); /** * Work mode. * @var string */ private static $mode = 'G'; /** * Allowed work modes. */ const WORK_MODE_GROUP = 'G'; const WORK_MODE_USER = 'U'; const WORK_MODE_TIMELINE = 'P'; const WORK_MODE_SPRINT = 'S'; /** * Returns DB table name for entity. * @return string */ public static function getTableName() { return 'b_tasks_stages'; } /** * Returns entity map definition. * @return array */ public static function getMap() { return array( 'ID' => new Entity\IntegerField('ID', array( 'primary' => true, 'autocomplete' => true )), 'TITLE' => new Entity\StringField('TITLE', array( // )), 'SORT' => new Entity\IntegerField('SORT', array( // )), 'COLOR' => new Entity\StringField('COLOR', array( // )), 'SYSTEM_TYPE' => new Entity\StringField('SYSTEM_TYPE', array( // )), 'ENTITY_ID' => new Entity\IntegerField('ENTITY_ID', array( // )), 'ENTITY_TYPE' => new Entity\StringField('ENTITY_TYPE', array( // )), 'ADDITIONAL_FILTER' => (new ArrayField('ADDITIONAL_FILTER', array( // )))->configureSerializationPhp(), 'TO_UPDATE' => (new ArrayField('TO_UPDATE', array( // )))->configureSerializationPhp(), 'TO_UPDATE_ACCESS' => new Entity\StringField('TO_UPDATE_ACCESS', array( // )), ); } /** * Check work mode. * @param string $mode Mode. * @return boolean */ public static function checkWorkMode($mode) { return $mode == self::WORK_MODE_GROUP || $mode == self::WORK_MODE_USER || $mode == self::WORK_MODE_TIMELINE || $mode == self::WORK_MODE_SPRINT; } /** * Set work mode. * @param string $mode New mode. * @return void */ public static function setWorkMode($mode) { if (self::checkWorkMode($mode)) { self::$mode = $mode; } } /** * Get work mode. * @return string */ public static function getWorkMode() { return self::$mode; } /** * Just delete by parent delete method. * @param int $id Stage id. * @return \Bitrix\Main\ORM\Data\DeleteResult */ public static function systemDelete($id) { return parent::delete($id); } /** * Base delete-method, first check that column is not system. * @param mixed $key Row key. * @param int $entityId Id of entity. * @return Entity\DeleteResult|false */ public static function delete($key, $entityId = 0) { $entityType = self::getWorkMode(); $res = self::getList(array( 'filter' => array( 'ID' => $key, 'ENTITY_ID' => $entityId, '=ENTITY_TYPE' => $entityType, //'=SYSTEM_TYPE' => false ) )); if ($stage = $res->fetch()) { // user can't delete first stage if ($stage['SYSTEM_TYPE'] == self::SYS_TYPE_NEW) { $result = new Entity\DeleteResult(); $result->addError(new Entity\EntityError( Loc::getMessage('TASKS_STAGE_ERROR_CANT_DELETE_FIRST'), 'CANT_DELETE_FIRST' )); return $result; } $res = parent::delete($stage['ID']); // remove tasks from this stage if ($res->isSuccess()) { if ($entityType == self::WORK_MODE_GROUP) { $resT = Task::getList(array( 'select' => array('ID'), 'filter' => array( 'STAGE_ID' => $stage['ID'] ) )); while ($row = $resT->fetch()) { Task::update($row['ID'], array( 'STAGE_ID' => 0 )); } } elseif ($entityType == self::WORK_MODE_USER) { $resT = TaskStageTable::getList(array( 'filter' => array( 'STAGE_ID' => $stage['ID'] ) )); while ($row = $resT->fetch()) { TaskStageTable::delete($row['ID']); } } } return $res; } return false; } /** * Get stages and create default. * @param int $entityId Id of entity. * @param bool $disableCreate Return stages as is without create defaults. * @return array */ public static function getStages($entityId = 0, $disableCreate = false) { static $stages = array(); $entityType = self::getWorkMode(); if ( isset($stages[$entityType.$entityId]) && !empty($stages[$entityType.$entityId]) ) { return $stages[$entityType.$entityId]; } $stages[$entityType.$entityId] = array(); $predefinedStages = ($entityType == self::WORK_MODE_TIMELINE) ? TimeLineTable::getStages() : []; $res = self::getList(array( 'filter' => array( 'ENTITY_ID' => $entityId, '=ENTITY_TYPE' => $entityType ), 'order' => array( 'SORT' => 'ASC' ) )); while ($row = $res->fetch()) { // set default color if ($row['COLOR'] == '') { $row['COLOR'] = self::DEF_COLOR_STAGE; } // set default title if ($row['TITLE'] == '') { if ($row['SYSTEM_TYPE'] != '') { $row['TITLE'] = Loc::getMessage('TASKS_STAGE_' . $row['SYSTEM_TYPE']); } else { $row['TITLE'] = Loc::getMessage('TASKS_STAGE_' . self::SYS_TYPE_DEFAULT); } } if ($row['SYSTEM_TYPE']) { if ( !$row['ADDITIONAL_FILTER'] && isset($predefinedStages[$row['SYSTEM_TYPE']]['FILTER']) ) { $row['ADDITIONAL_FILTER'] = $predefinedStages[$row['SYSTEM_TYPE']]['FILTER']; $row['ADDITIONAL_FILTER_TEST'] = $row['ADDITIONAL_FILTER']; } if (isset($row['ADDITIONAL_FILTER_TEST'])) { foreach ($row['ADDITIONAL_FILTER_TEST'] as &$date) { if ($date instanceof \Bitrix\Main\Type\DateTime) { $date = clone $date; $date = (string)$date; } } unset($date); } if ( !$row['TO_UPDATE'] && isset($predefinedStages[$row['SYSTEM_TYPE']]['UPDATE']) ) { $row['TO_UPDATE'] = $predefinedStages[$row['SYSTEM_TYPE']]['UPDATE']; } if ( !$row['TO_UPDATE_ACCESS'] && isset($predefinedStages[$row['SYSTEM_TYPE']]['UPDATE_ACCESS']) ) { $row['TO_UPDATE_ACCESS'] = $predefinedStages[$row['SYSTEM_TYPE']]['UPDATE_ACCESS']; } } $row['TO_UPDATE'] = (array)$row['TO_UPDATE']; $row['ADDITIONAL_FILTER'] = (array)$row['ADDITIONAL_FILTER']; $stages[$entityType.$entityId][$row['ID']] = $row; } if ($disableCreate) { return $stages[$entityType.$entityId]; } // if empty, create default stages if (empty($stages[$entityType.$entityId])) { if ($entityType == self::WORK_MODE_USER) { self::add(array( 'SYSTEM_TYPE' => self::SYS_TYPE_NEW, 'TITLE' => Loc::getMessage('TASKS_STAGE_MP_1'), 'SORT' => 100, 'ENTITY_ID' => $entityId, 'ENTITY_TYPE' => $entityType, 'COLOR' => '00C4FB' )); self::add(array( 'TITLE' => Loc::getMessage('TASKS_STAGE_MP_2'), 'SORT' => 200, 'ENTITY_ID' => $entityId, 'ENTITY_TYPE' => $entityType, 'COLOR' => '47D1E2' )); } else if ($entityType == self::WORK_MODE_GROUP) { if ($entityId > 0) { self::getStages(0); self::copyView(0, $entityId); } else { self::add(array( 'SYSTEM_TYPE' => self::SYS_TYPE_NEW, 'SORT' => 100, 'ENTITY_ID' => $entityId, 'ENTITY_TYPE' => $entityType, 'COLOR' => '00C4FB' )); self::add(array( 'SYSTEM_TYPE' => self::SYS_TYPE_PROGRESS, 'SORT' => 200, 'ENTITY_ID' => $entityId, 'ENTITY_TYPE' => $entityType, 'COLOR' => '47D1E2' )); self::add(array( 'SYSTEM_TYPE' => self::SYS_TYPE_FINISH, 'SORT' => 300, 'ENTITY_ID' => $entityId, 'ENTITY_TYPE' => $entityType, 'COLOR' => '75D900' )); } } else { $i = 0; if ($entityType == self::WORK_MODE_TIMELINE) { $source = TimeLineTable::getStages(); } else if ($entityType == self::WORK_MODE_SPRINT) { $source = SprintTable::getStages($entityId); } else { return []; } foreach ($source as $stageCode => $stageItem) { self::add([ 'SYSTEM_TYPE' => array_key_exists('SYSTEM_TYPE', $stageItem) ? $stageItem['SYSTEM_TYPE'] : $stageCode, 'TITLE' => array_key_exists('TITLE', $stageItem) ? $stageItem['TITLE'] : '', 'SORT' => ++$i * 100, 'ENTITY_ID' => $entityId, 'ENTITY_TYPE' => $entityType, 'COLOR' => $stageItem['COLOR'] ]); } } return self::getStages($entityId); } return $stages[$entityType.$entityId]; } /** * Add or update stages by code/id. * @param int $id Stage id. * @param array $fields Data array. * @return res Database result. */ public static function updateByCode($id, $fields) { $id = intval($id); $afterId = isset($fields['AFTER_ID']) ? intval($fields['AFTER_ID']) : 0; $entityId = isset($fields['ENTITY_ID']) ? intval($fields['ENTITY_ID']) : 0; $entityType = self::getWorkMode(); if ($entityType == self::WORK_MODE_TIMELINE) { return null; } // get stages $newStageId = 0; $stages = array(); $res = self::getList(array( 'filter' => array( 'ENTITY_ID' => $entityId, '=ENTITY_TYPE' => $entityType ), 'order' => array( 'SORT' => 'ASC' ) )); while ($row = $res->fetch()) { if ($row['SYSTEM_TYPE'] == self::SYS_TYPE_NEW) { $newStageId = $row['ID']; } $stages[$row['ID']] = $row; } // if move first - update tasks for fix in this stage if ( isset($fields['AFTER_ID']) && isset($stages[$id]) && $entityType == self::WORK_MODE_GROUP ) { if ( $fields['AFTER_ID'] == 0 || $stages[$id]['SYSTEM_TYPE'] == self::SYS_TYPE_NEW ) { $connection = \Bitrix\Main\Application::getConnection(); $sql = 'UPDATE ' . '`' . Task::getTableName() . '` ' . 'SET `STAGE_ID`=' . ($newStageId) . ' ' . 'WHERE `STAGE_ID`=0 AND `GROUP_ID`=' . $entityId . ';'; $connection->query($sql); } } // set new if (!isset($stages[$id])) { $id = 0; } $stages[$id] = array_merge( isset($stages[$id]) ? $stages[$id] : array(), $fields ); // set sort if (array_key_exists('AFTER_ID', $fields)) { if ($afterId == 0) { $stages[$id]['SORT'] = 10; } elseif (isset($stages[$afterId])) { $stages[$id]['SORT'] = $stages[$afterId]['SORT'] + 10; } else { $stages[$id]['SORT'] = count($stages) * 100 + 10; } } uasort($stages, function($a, $b) { if ($a['SORT'] == $b['SORT']) { return 0; } return ($a['SORT'] < $b['SORT']) ? -1 : 1; }); // renew $return = null; $sort = 100; foreach ($stages as $i => $stage) { if ( $stage['TITLE'] || $stage['SYSTEM_TYPE'] == self::SYS_TYPE_NEW ) { $stage['SYSTEM_TYPE'] = ''; } $fields = array( 'TITLE' => $stage['TITLE'], 'COLOR' => $stage['COLOR'], 'ENTITY_ID' => $stage['ENTITY_ID'], 'ENTITY_TYPE' => $entityType, 'SORT' => $sort, 'SYSTEM_TYPE' => $sort == 100 ? self::SYS_TYPE_NEW : $stage['SYSTEM_TYPE'] ); $sort += 100; if ($i > 0) { $res = self::update($i, $fields); } else { $res = self::add($fields); } if ($i == $id) { $return = $res; } } return $return; } /** * Get stages id by stage code. * @param int $id Id of stage. * @param int $entityId Id of entity. * @return int|array */ public static function getStageIdByCode($id, $entityId = 0) { if (self::getWorkMode() == self::WORK_MODE_USER) { return $id; } $stages = self::getStages($entityId); if (isset($stages[$id])) { $stage = $stages[$id]; switch ($stage['SYSTEM_TYPE']) { case self::SYS_TYPE_NEW: return array($stage['ID'], 0); default: return $stage['ID']; } } return -1; } /** * Get default stage id. * @param int $id Entity id. * @return int */ public static function getDefaultStageId($id = 0) { foreach (self::getStages($id) as $stage) { if ($stage['SYSTEM_TYPE'] == self::SYS_TYPE_NEW) { return $stage['ID']; } } return -1; } /** * Group tasks by filter and return counts for each stage. * @param array $filter Filter for tasks. * @param boolean $userId Context user id. * @return \DatabaseResult */ public static function getStagesCount(array $filter = array(), $userId = false) { if ($userId === false) { $userId = \Bitrix\Tasks\Util\User::getId(); } $userId = intval($userId); // related joins $relatedJoins = \CTasks::getRelatedJoins([], $filter, [], ['USER_ID' => $userId]); $filterKeys = \CTasks::GetFilteredKeys($filter); $joinTaskMember = in_array('MEMBER', $filterKeys); if ($joinTaskMember) { unset($filter['::SUBFILTER-ROLEID']['MEMBER']); $relatedJoins['MEMBER'] = "INNER JOIN ( SELECT TMM.TASK_ID, TMM.USER_ID FROM " . MemberTable::getTableName() . " TMM WHERE TMM.USER_ID = {$userId} GROUP BY TMM.TASK_ID ) TM ON TM.TASK_ID = STG.TASK_ID"; } // common $sqlSearch = \CTasks::GetFilter($filter, "", array('TASK_MEMBER_JOINED' => $joinTaskMember)); // uf fields $userFieldsSql = new \CUserTypeSQL(); $userFieldsSql->setEntity('TASKS_TASK', 'T.ID'); $userFieldsSql->setFilter($filter); $ufFilterSql = $userFieldsSql->getFilter(); if ($ufFilterSql != '') { $sqlSearch[] = '(' . $ufFilterSql . ')'; } $sql = " SELECT STG.STAGE_ID, COUNT(STG.STAGE_ID) AS CNT FROM ("; // if personal - search in another table if ( self::getWorkMode() == self::WORK_MODE_USER || self::getWorkMode() == self::WORK_MODE_SPRINT ) { $sql .= " SELECT STG.STAGE_ID FROM " . TaskStageTable::getTableName() . " STG LEFT JOIN " . Task::getTableName() . " T ON T.ID = STG.TASK_ID " . implode("\n", $relatedJoins) . " " . $userFieldsSql->GetJoin("T.ID") . " " . "WHERE " . implode(' AND ', $sqlSearch) . " " . "GROUP BY T.ID, STG.STAGE_ID "; } // else tasks table else { if (array_key_exists('MEMBER', $relatedJoins)) { unset($relatedJoins['MEMBER']); } $sql .= " SELECT T.STAGE_ID FROM " . Task::getTableName() . " T " . implode("\n", $relatedJoins) . " " . $userFieldsSql->GetJoin("T.ID") . " " . "WHERE " . implode(' AND ', $sqlSearch) . " " . "GROUP BY T.ID, T.STAGE_ID "; } $sql .= ") STG GROUP BY STG.STAGE_ID "; return \Bitrix\Main\Application::getConnection()->query($sql); } /** * Copy view from one entity to another. * @param int $fromEntityId From entity Id. * @param int $toEntityId To entity Id. * @param string $entityType Entity type. * @return array|bool * @throws \Bitrix\Main\ArgumentException * @throws \Bitrix\Main\ObjectPropertyException * @throws \Bitrix\Main\SystemException */ public static function copyView($fromEntityId, $toEntityId, $entityType = self::WORK_MODE_GROUP) { if ( $fromEntityId != $toEntityId && ( $entityType == self::WORK_MODE_USER || $entityType == self::WORK_MODE_GROUP || $entityType == self::WORK_MODE_SPRINT ) ) { $result = []; $res = self::getList(array( 'filter' => array( 'ENTITY_ID' => $fromEntityId, '=ENTITY_TYPE' => $entityType ), 'order' => array( 'ID' => 'ASC' ) )); while ($row = $res->fetch()) { $oldStageId = $row['ID']; if (!$row['TITLE']) { $row['TITLE'] = $row['TITLE'] = Loc::getMessage('TASKS_STAGE_' . $row['SYSTEM_TYPE']); } if ( $row['SYSTEM_TYPE'] && ($row['SYSTEM_TYPE'] != self::SYS_TYPE_NEW) ) { unset($row['SYSTEM_TYPE']); } unset($row['ID']); $row['ENTITY_ID'] = $toEntityId; $newStageId = (($addResult = self::add($row)) ? $addResult->getId() : false); $result[$oldStageId] = $newStageId; } return $result; } return false; } /** * Disable pin in stage for user. * @param int|array $userIds User id. * @return void */ public static function disablePinForUser($userIds) { if (!is_array($userIds)) { $userIds = array($userIds); } self::$disablePin = array_merge(self::$disablePin, $userIds); } /** * Disable link in stage for user. * @param int|array $userIds User id. * @return void */ public static function disableLinkForUser($userIds) { if (!is_array($userIds)) { $userIds = array($userIds); } self::$disableLink = array_merge(self::$disableLink, $userIds); } /** * Pin the task in the DEFAULT stage for users/group. * @param int $taskId Task id. * @param int|array $users Pin for users. * @param boolean $refreshGroup Refresh sorting in group. * @return void */ public static function pinInStage($taskId, $users = array(), $refreshGroup = false) { if (!is_array($users)) { $users = array($users); } $newTask = empty($users); // get additional data $currentUsers = array(); $res = \CTasks::getList(array( // ), array( 'ID' => $taskId, 'CHECK_PERMISSIONS' => 'N' ), array( 'ID', 'GROUP_ID', 'STAGE_ID', 'RESPONSIBLE_ID', 'CREATED_BY' ) ); if (($task = $res->fetch())) { $currentUsers[] = $task['RESPONSIBLE_ID']; $currentUsers[] = $task['CREATED_BY']; } else { return; } // prepare sort/filter $sort = array( 'SORTING' => 'ASC', 'STATUS_COMPLETE' => 'ASC', 'DEADLINE' => 'ASC,NULLS', 'ID' => 'ASC' ); $filter = array( 'CHECK_PERMISSIONS' => 'N', 'ONLY_ROOT_TASKS' => 'N', 'GROUP_ID' => $task['GROUP_ID'], '!ID' => $taskId ); // get current other members $res = \CTaskMembers::GetList( array(), array('TASK_ID' => $taskId) ); while ($row = $res->fetch()) { $currentUsers[] = $row['USER_ID']; } if ($newTask) { $users = $currentUsers; $currentUsers = array(); } $users = array_unique($users); // pin in personal default stage (if already Kanban exist) $personaleDefStages = array(); self::setWorkMode(self::WORK_MODE_USER); foreach ($users as $userId) { $checkStages = self::getStages($userId, true); if (!empty($checkStages)) { $personaleDefStages[$userId] = self::getDefaultStageId($userId); if (!in_array($userId, self::$disableLink)) { $resStg = TaskStageTable::getList(array( 'filter' => array( 'TASK_ID' => $taskId, 'STAGE_ID' => array_keys($checkStages) ) )); if (!$resStg->fetch()) { $fields = array( 'TASK_ID' => $taskId, 'STAGE_ID' => self::getDefaultStageId($userId) ); if (!TaskStageTable::getList(array( 'filter' => $fields ) )->fetch()) { try { TaskStageTable::add($fields); } catch (\Exception $e){} } } } } } // work mode self::setWorkMode( $task['GROUP_ID'] > 0 ? self::WORK_MODE_GROUP : self::WORK_MODE_USER ); if ($task['GROUP_ID'] > 0 && ($newTask || $refreshGroup)) { $checkStages = self::getStages($task['GROUP_ID'], true); } else { $checkStages = array(); } // one sort for project if ($task['GROUP_ID'] > 0 && !empty($checkStages) && ($newTask || $refreshGroup)) { // get order if (($project = ProjectsTable::getById($task['GROUP_ID'])->fetch())) { $order = $project['ORDER_NEW_TASK'] ? $project['ORDER_NEW_TASK'] : 'desc'; } else { $order = 'desc'; } if ($order == 'asc') { $sort = array( 'SORTING' => 'DESC', 'STATUS_COMPLETE' => 'DESC', 'DEADLINE' => 'DESC', 'ID' => 'DESC' ); } // set sorting $res = \CTasks::getList( $sort, $filter, array('ID', 'TITLE'), array( 'NAV_PARAMS' => array( 'nTopCount' => 1 ), 'SORTING_GROUP_ID' => $task['GROUP_ID'] ) ); if ($row = $res->fetch()) { SortingTable::setSorting( \Bitrix\Tasks\Util\User::getId() > 0 ? \Bitrix\Tasks\Util\User::getId() : $task['CREATED_BY'], $task['GROUP_ID'], $taskId, $row['ID'], $order == 'asc' ? false : true ); } } // and for each user foreach ($users as $userId) { if ( !in_array($userId, self::$disablePin) && !in_array($userId, $currentUsers) && isset($personaleDefStages[$userId]) ) { // get order $order = \CUserOptions::getOption( 'tasks', 'order_new_task', 'desc', $userId ); if ($order == 'asc') { $sort = array( 'SORTING' => 'DESC', 'STATUS_COMPLETE' => 'DESC', 'DEADLINE' => 'DESC', 'ID' => 'DESC' ); } else { $sort = array( 'SORTING' => 'ASC', 'STATUS_COMPLETE' => 'ASC', 'DEADLINE' => 'ASC,NULLS', 'ID' => 'ASC' ); } // set sorting unset($filter['GROUP_ID']); $filter['MEMBER'] = $userId; $res = \CTasks::getList( $sort, $filter, array('ID'), array( 'NAV_PARAMS' => array( 'nTopCount' => 1 ), 'USER_ID' => $userId ) ); if ($row = $res->fetch()) { SortingTable::setSorting( $userId, 0, $taskId, $row['ID'], $order == 'asc' ? false : true ); } } } } /** * Pin the task in the stage for user/group. * @param int $taskId Task id. * @param int $stageId Stage id. * @return void */ public static function pinInTheStage($taskId, $stageId) { if (($stage = StagesTable::getById($stageId)->fetch())) { $order = 'desc'; // get order if ($stage['ENTITY_TYPE'] == self::WORK_MODE_GROUP) { if (($project = ProjectsTable::getById($stage['ENTITY_ID'])->fetch())) { $order = $project['ORDER_NEW_TASK'] ? $project['ORDER_NEW_TASK'] : 'desc'; } } else { $order = \CUserOptions::getOption( 'tasks', 'order_new_task', 'desc', $stage['ENTITY_ID'] ); } // set order if ($order == 'desc') { $sort = array( 'SORTING' => 'ASC', 'STATUS_COMPLETE' => 'ASC', 'DEADLINE' => 'ASC,NULLS', 'ID' => 'ASC' ); } else { $sort = array( 'SORTING' => 'DESC', 'STATUS_COMPLETE' => 'DESC', 'DEADLINE' => 'DESC', 'ID' => 'DESC' ); } // set filter $filter = array( 'CHECK_PERMISSIONS' => 'N', 'ONLY_ROOT_TASKS' => 'N', '!ID' => $taskId ); if ($stage['ENTITY_TYPE'] == self::WORK_MODE_GROUP) { $filter['GROUP_ID'] = $stage['ENTITY_ID']; } else { $filter['MEMBER'] = $stage['ENTITY_ID']; } // set params $params = array( 'NAV_PARAMS' => array( 'nTopCount' => 1 ) ); if ($stage['ENTITY_TYPE'] == self::WORK_MODE_GROUP) { $params['SORTING_GROUP_ID'] = $stage['ENTITY_ID']; } else { $params['USER_ID'] = $stage['ENTITY_ID']; } // set sorting $res = \CTasks::getList( $sort, $filter, array('ID'), $params ); if ($row = $res->fetch()) { if ($stage['ENTITY_TYPE'] == self::WORK_MODE_GROUP) { $userId = \Bitrix\Tasks\Util\User::getId(); $groupId = $stage['ENTITY_ID']; } else { $userId = $stage['ENTITY_ID']; $groupId = 0; } SortingTable::setSorting( $userId, $groupId, $taskId, $row['ID'], $order == 'asc' ? false : true ); } } } /** * Delete all stages and sprints of group after group delete. * @param int $groupId Group id. * @return void */ public static function onSocNetGroupDelete($groupId) { $res = self::getList(array( 'filter' => array( 'ENTITY_ID' => $groupId, '=ENTITY_TYPE' => self::WORK_MODE_GROUP ) )); while ($row = $res->fetch()) { parent::delete($row['ID']); } $res = SprintTable::getList([ 'filter' => [ 'GROUP_ID' => $groupId ] ] ); while ($row = $res->fetch()) { SprintTable::delete($row['ID']); } } /** * Delete all stages of user after user delete. * @param int $userId User id. * @return void */ public static function onUserDelete($userId) { $res = self::getList(array( 'filter' => array( 'ENTITY_ID' => $userId, '=ENTITY_TYPE' => [ self::WORK_MODE_USER, self::WORK_MODE_TIMELINE ] ) )); while ($row = $res->fetch()) { parent::delete($row['ID']); } } /** * On stage delete. * @param Entity\Event $event Event. * @return void */ public static function onDelete(Entity\Event $event) { $primary = $event->getParameter('id'); TaskStageTable::clearStage($primary['ID']); } }