- Модуль: timeman
- Путь к файлу: ~/bitrix/modules/timeman/lib/update/timemanversion19converter.php
- Класс: BitrixTimemanUpdateTimemanVersion19Converter
- Вызов: TimemanVersion19Converter::migrateSchedulesSettings
private function migrateSchedulesSettings()
{
$this->createTemporaryTables();
$this->logMessage('migrate Schedules Settings started', __LINE__);
try
{
$this->deleteOldSchedules();
}
catch (MaximumExecutionSecondsExceededException $exc)
{
$this->logMessage('Maximum Execution Seconds Exceeded Exception - deleteOldSchedules', __LINE__);
return false;
}
$defaultSettings = $this->getDefaultTimemanSettings();
$departmentsTree = $this->buildDepartmentsTree();
$commonScheduleForm = $this->createOrRestoreSchedulesData(reset(array_keys($departmentsTree)));
# fetch all users/departments personal timeman settings
# and group them
try
{
$this->logMessage(json_encode($departmentsTree), __LINE__);
}
catch (Exception $exc)
{
}
try
{
foreach ($departmentsTree as $departmentId => $departmentData)
{
$this->processDepartmentScheduleMigration(
$departmentData,
$defaultSettings,
[(int)$departmentId]
);
}
}
catch (MaximumExecutionSecondsExceededException $exc)
{
$this->logMessage('Maximum Execution Seconds Exceeded Exception - saveTempDataForRestore', __LINE__);
# save results in a temp table
# that on the next run we can start from this point and continue grouping
$this->saveTempDataForRestore();
return false;
}
foreach ($this->scheduleForms as $key => $scheduleForm)
{
$scheduleForm->validate();
if ($this->isMaxExecutionSecondsExceeded())
{
$this->saveTempDataForRestore();
return false;
}
if ($this->savedSchedulesMap[$key]['scheduleId'] > 0)
{
// schedule already saved to db
continue;
}
$result = DependencyManager::getInstance()
->getScheduleService()
->add($scheduleForm);
if ($result->isSuccess())
{
$this->savedSchedulesMap[$key] = [
'scheduleId' => $result->getSchedule()->getId(),
'shiftId' => $result->getSchedule()->getShifts() ? reset($result->getSchedule()->getShifts()->getIdList()) : 0,
'usersUpdated' => false,
];
}
}
$this->logMessage('schedules added', __LINE__);
$commonScheduleId = 0;
foreach ($this->scheduleForms as $scheduleFormKey => $scheduleForm)
{
if ($scheduleForm->isForAllUsers)
{
$commonScheduleId = (int)$this->savedSchedulesMap[$scheduleFormKey]['scheduleId'];
break;
}
}
$violationRows = [];
foreach ($this->violationForms as $entityCode => $violationForm)
{
$violationForm->validate();
$violationRules = ViolationRules::create($commonScheduleId, $violationForm, $entityCode);
$violationRows[] = [
'SCHEDULE_ID' => $violationRules->getScheduleId(),
'ENTITY_CODE' => Application::getConnection()->getSqlHelper()->forSql($violationRules->getEntityCode()),
'MAX_EXACT_START' => (int)$violationRules->getMaxExactStart(),
'MIN_EXACT_END' => (int)$violationRules->getMinExactEnd(),
'MIN_DAY_DURATION' => (int)$violationRules->getMinDayDuration(),
'MAX_ALLOWED_TO_EDIT_WORK_TIME' => (int)$violationRules->getMaxAllowedToEditWorkTime(),
'USERS_TO_NOTIFY' => $violationRules->getUsersToNotify(),
];
}
if (!empty($violationRows) && $commonScheduleId > 0 && !$this->violationRulesSaved)
{
if (!empty(array_column($violationRows, 'ENTITY_CODE')))
{
Application::getConnection()->query("DELETE FROM `" . ViolationRulesTable::getTableName() . "`
WHERE SCHEDULE_ID = " . (int)$commonScheduleId
. ' AND ENTITY_CODE IN ("' . implode('", "', array_column($violationRows, 'ENTITY_CODE')) . '")'
);
}
$resultMulti = ViolationRulesTable::addMulti($violationRows, true);
if ($resultMulti->isSuccess())
{
Application::getConnection()->query("UPDATE b_timeman_converter_violation_rules SET VIOLATION_RULES_SAVED = 1");
$this->violationRulesSaved = true;
}
}
if ($this->isMaxExecutionSecondsExceeded())
{
$this->saveTempDataForRestore();
return false;
}
# build mapping - for every userId find scheduleId by user's settings
foreach ($departmentsTree as $departmentId => $departmentData)
{
$this->saveUserToScheduleMap($departmentData, 'department');
}
# build mapping - scheduleId to array of userIds
$scheduleKeyUserIdsMap = [];
foreach ($this->userToScheduleMap as $userId => $userScheduleKey)
{
$scheduleKeyUserIdsMap[$userScheduleKey][] = (int)$userId;
}
foreach ($scheduleKeyUserIdsMap as $scheduleKey => $userIds)
{
if ($this->isMaxExecutionSecondsExceeded())
{
$this->saveTempDataForRestore();
return false;
}
if ($this->savedSchedulesMap[$scheduleKey]['usersUpdated'] === true)
{
# columns SCHEDULE_ID and SHIFT_ID are already updated
continue;
}
$chunks = array_chunk($userIds, 500);
foreach ($chunks as $chunkUserIds)
{
Application::getConnection()->query("
UPDATE b_timeman_entries
SET
TIMESTAMP_X = TIMESTAMP_X,
SCHEDULE_ID = " . (int)$this->savedSchedulesMap[$scheduleKey]['scheduleId'] . ",
SHIFT_ID = " . (int)$this->savedSchedulesMap[$scheduleKey]['shiftId'] . "
WHERE USER_ID IN (" . implode(', ', $chunkUserIds) . ');'
);
$this->savedSchedulesMap[$scheduleKey]['usersUpdated'] = true;
}
}
$this->logMessage('update SCHEDULE_ID for records - done', __LINE__);
# just to prevent any record data with no scheduleId mapping
foreach ($this->scheduleForms as $scheduleFormKey => $scheduleForm)
{
if ($scheduleForm->isForAllUsers)
{
Application::getConnection()->query("
UPDATE b_timeman_entries
SET
TIMESTAMP_X = TIMESTAMP_X,
SCHEDULE_ID = " . (int)$this->savedSchedulesMap[$scheduleFormKey]['scheduleId'] . ",
SHIFT_ID = " . (int)$this->savedSchedulesMap[$scheduleFormKey]['shiftId'] . "
WHERE SCHEDULE_ID = 0;"
);
break;
}
}
Application::getConnection()->query("DROP TABLE `b_timeman_converter_collected_schedules`;");
Application::getConnection()->query("DROP TABLE `b_timeman_converter_violation_rules`;");
Application::getConnection()->query("DROP TABLE `b_timeman_converter_processed_entities`;");
if ($this->dropLogAfterExecution)
{
Application::getConnection()->query("DROP TABLE `b_timeman_converter_log`;");
}
$this->logMessage('DROP helpers tables - done', __LINE__);
return true;
}