return "Нет доступа";
}
$model = Admin::findOne($id);
-
++
+ // Определяем специальные группы работников (используется в POST обработке и при рендеринге)
+ $workersGroup = AdminGroup::getWorkersGroups();
-
++
if (Yii::$app->user->can("updateAdminSettings", ['id' => $model->id])) {
if (Yii::$app->request->isPost) {
$attributes = Yii::$app->request->post()['Admin'];
unset($attributes['storeArray']);
$attributes['store_arr_guid'] = empty($attributes['storeGuidArray']) ? '' : implode(',', $attributes['storeGuidArray']);
unset($attributes['storeGuidArray']);
- if (!Yii::$app->user->can("updateAdminSettingsGroupId", ['group_id' => $attributes['group_id']])) {
- unset($attributes['group_id']);
-
++
+ // Проверяем права на изменение group_id
+ // Если group_id не передан в POST, используем текущий из модели
+ $newGroupId = $attributes['group_id'] ?? $model->group_id;
-
++
+ // Проверяем права только если group_id действительно меняется
+ if ($newGroupId != $model->group_id) {
+ $canChangeGroupId = Yii::$app->user->can("updateAdminSettingsGroupId", ['group_id' => $newGroupId]);
-
++
+ // Если нет прав на изменение group_id - используем текущий group_id из модели
+ if (!$canChangeGroupId) {
+ $attributes['group_id'] = $model->group_id;
+ }
}
-
if (!Yii::$app->user->can("updateAdminSettingsOnlyByHrAndAdministrator")) {
unset($attributes['store_dostup_all']);
unset($attributes['store_id']);
Yii::$app->cache->set("dirtyAuthSettings", true);
}
- // Определяем специальные группы с parent_id = 50
- $specialGroups = [
- AdminGroup::GROUP_FLORIST_DAY, // 30
- AdminGroup::GROUP_FLORIST_NIGHT, // 35
- AdminGroup::GROUP_FLORIST_SUPPORT_DAY, // 40
- AdminGroup::GROUP_WORKERS, // 45
- AdminGroup::GROUP_ADMINISTRATORS, // 50
- AdminGroup::GROUP_FLORIST_SUPPORT_NIGHT, // 72
- AdminGroup::GROUP_FLORIST, // 89
- ];
-
- // Ищем группу "Работники магазинов" по имени
- $workersGroup = AdminGroup::find()->where(['name' => AdminGroup::GROUP_STORE_WORKERS_NAME])->one();
- if ($workersGroup) {
- $specialGroups[] = $workersGroup->id;
- }
+ // Получаем группу один раз для всех последующих операций
+ $currentGroup = AdminGroup::findOne($attributes['group_id']);
+ $isSpecialGroup = in_array((int)$attributes['group_id'], $workersGroup);
-
+
- $isSpecialGroup = in_array((int)$attributes['group_id'], $specialGroups);
-
- if ($isSpecialGroup) {
- // Для специальных групп формируем group_name из employee_position + shift
- if (!empty($attributes['employee_position_id'])) {
- $employeePosition = EmployeePosition::findOne($attributes['employee_position_id']);
- if ($employeePosition) {
- $groupName = $employeePosition->name;
- // Если выбрана смена, добавляем её к названию
- if (!empty($attributes['shift'])) {
- $groupName .= ' ' . $attributes['shift'];
- }
- $attributes['group_name'] = $groupName;
- }
- }
+ // Устанавливаем group_name из AdminGroup->name
+ if ($currentGroup) {
+ $attributes['group_name'] = $currentGroup->name;
+ } else if (isset($attributes['custom_position'])) {
+ // Если группа не найдена, используем текстовое поле как fallback
+ $attributes['group_name'] = $attributes['custom_position'];
+ }
-
+
- // Очищаем shift для не-специальных групп
- unset($attributes['shift']);
- } else {
- // Для остальных групп group_name берем из текстового поля
- if (isset($attributes['custom_position'])) {
- $attributes['group_name'] = $attributes['custom_position'];
- unset($attributes['custom_position']);
- }
- // Очищаем employee_position_id и shift для не-специальных групп
+ // Для не-специальных групп очищаем employee_position_id
+ if (!$isSpecialGroup) {
$attributes['employee_position_id'] = null;
- unset($attributes['shift']);
}
-
+
+ // Очищаем custom_position в любом случае
+ unset($attributes['custom_position']);
+
$model->setAttributes($attributes, false);
if (Yii::$app->user->can("manageAvatarka", ['id' => $model->id])) {
}
}
- $adminGroups = [AdminGroup::NOT_INITIALIZED_GROUP => 'Не выбрана'];
- foreach (AdminGroup::find()->all() as $adminGroupId => $adminGroup) {
- $adminGroups[$adminGroup->id] = $adminGroup->name;
- }
- $adminGroups = [AdminGroup::NOT_INITIALIZED_GROUP => 'Не выбрана'] +
++ $adminGroups = [AdminGroup::NOT_INITIALIZED_GROUP => 'Не выбрана'] +
+ ArrayHelper::map(AdminGroup::find()->all(), 'id', 'name');
- $adminArr = [];
- foreach (Admin::find()->with('adminGroup')->all() as $admin) {
- $adminArr[] = ['id' => $admin->id, 'name' => $admin->name, 'groupName' => $admin->adminGroup->name ?? "Другие"];
- }
+ $admins = ArrayHelper::map(
- Admin::find()->with('adminGroup')->all(),
- 'id',
- 'name',
++ Admin::find()->with('adminGroup')->all(),
++ 'id',
++ 'name',
+ function($model) {
+ return $model->adminGroup->name ?? 'Другие';
+ }
+ );
- $admins = ArrayHelper::map($adminArr, 'id', 'name', 'groupName');
$positions = EmployeePosition::find()->orderBy('posit')->all();
$cityStores = ArrayHelper::map(CityStore::find()->select(['id', 'name'])->all(), 'id', 'name');
$shift_id = $data->shift_type == 0 ? [1, 2, 5, 8] : ($data->shift_type == 1 ? [1, 5, 8] : [2]);
- $timetablesMonth = Timetable::find()->alias('t')->select(['admin_id', 'a.name as adminName', 't.store_id', 't.shift_id'])
- ->innerJoin('admin a', 'admin_id = a.id')
- ->where(['t.store_id' => $data->stores])
+ // Получаем сотрудников из фактических смен за месяц
+ $timetablesMonthData = TimetableFactModel::find()
+ ->select(['admin_id', 'store_id', 'shift_id'])
+ ->where(['store_id' => $data->stores])
->andWhere(['>=', 'date', date("Y-m-01", strtotime($currentDate))])
->andWhere(['<=', 'date', $currentDate])
- ->andWhere(['shift_id' => $shift_id, 'tabel' => 0, 'slot_type_id' => Timetable::TIMESLOT_WORK])
- ->andWhere(['t.active' => 1])
- ->asArray()->all();
+ ->andWhere(['shift_id' => $shift_id])
+ ->andWhere(['>', 'work_time', 0])
+ ->groupBy(['admin_id', 'store_id', 'shift_id'])
+ ->asArray()
+ ->all();
+
+ // Если в факте нет данных за месяц, используем план как fallback
+ if (empty($timetablesMonthData)) {
+ $timetablesMonthData = Timetable::find()->alias('t')
+ ->select(['admin_id', 'store_id', 'shift_id'])
+ ->where(['t.store_id' => $data->stores])
+ ->andWhere(['>=', 't.date', date("Y-m-01", strtotime($currentDate))])
+ ->andWhere(['<=', 't.date', $currentDate])
+ ->andWhere(['t.shift_id' => $shift_id, 'tabel' => 0, 'slot_type_id' => Timetable::TIMESLOT_WORK])
+ ->groupBy(['admin_id', 'store_id', 'shift_id'])
+ ->asArray()
+ ->all();
+ }
- $timetables = Timetable::find()->alias('t')->select(['admin_id', 'a.name as adminName', 't.store_id', 't.shift_id'])
- ->innerJoin('admin a', 'admin_id = a.id')
- ->where(['t.store_id' => $data->stores])
- ->andWhere(['date' => $currentDate, 'tabel' => 0])
- ->andWhere(['shift_id' => $shift_id, 'slot_type_id' => Timetable::TIMESLOT_WORK])
- ->andWhere(['t.active' => 1])
- ->asArray()->all();
+ // Получаем сотрудников из фактических смен за день
+ $timetablesData = TimetableFactModel::find()
+ ->select(['admin_id', 'store_id', 'shift_id'])
+ ->where(['store_id' => $data->stores])
+ ->andWhere(['date' => $currentDate])
+ ->andWhere(['shift_id' => $shift_id])
+ ->andWhere(['>', 'work_time', 0])
+ ->groupBy(['admin_id', 'store_id', 'shift_id'])
+ ->asArray()
+ ->all();
+
+ // Если в факте нет данных, используем план как fallback
+ if (empty($timetablesData)) {
+ $timetablesData = Timetable::find()->alias('t')
+ ->select(['admin_id', 'store_id', 'shift_id'])
+ ->where(['t.store_id' => $data->stores])
+ ->andWhere(['t.date' => $currentDate, 'tabel' => 0])
+ ->andWhere(['t.shift_id' => $shift_id, 'slot_type_id' => Timetable::TIMESLOT_WORK])
+ ->groupBy(['admin_id', 'store_id', 'shift_id'])
+ ->asArray()
+ ->all();
+ }
- $adminIdsMonth = ArrayHelper::getColumn($timetablesMonth, 'admin_id');
- $adminIds = ArrayHelper::getColumn($timetables, 'admin_id');
+ // Получаем имена админов отдельным запросом
+ // Извлекаем уникальные ID администраторов для использования в последующих запросах
+ $adminIdsMonth = array_unique(ArrayHelper::getColumn($timetablesMonthData, 'admin_id'));
+ $adminIds = array_unique(ArrayHelper::getColumn($timetablesData, 'admin_id'));
+ $allAdminIds = array_unique(array_merge($adminIdsMonth, $adminIds));
-
++
+ $adminNamesMap = [];
+ if (!empty($allAdminIds)) {
+ $admins = Admin::find()
+ ->select(['id', 'name'])
+ ->where(['id' => $allAdminIds])
+ ->indexBy('id')
+ ->asArray()
+ ->all();
+ $adminNamesMap = ArrayHelper::map($admins, 'id', 'name');
+ }
+
+ // Формируем массивы с именами админов
+ $timetablesMonth = [];
+ foreach ($timetablesMonthData as $item) {
+ $timetablesMonth[] = [
+ 'admin_id' => $item['admin_id'],
+ 'adminName' => $adminNamesMap[$item['admin_id']] ?? '',
+ 'store_id' => $item['store_id'],
+ 'shift_id' => $item['shift_id'],
+ ];
+ }
+
+ $timetables = [];
+ foreach ($timetablesData as $item) {
+ $timetables[] = [
+ 'admin_id' => $item['admin_id'],
+ 'adminName' => $adminNamesMap[$item['admin_id']] ?? '',
+ 'store_id' => $item['store_id'],
+ 'shift_id' => $item['shift_id'],
+ ];
+ }
// Подсчет должностей на смене для этого дня
$employeePositionsOnShift = $this->countEmployeesByPosition($timetables, $positionMap);
$adminNames = [];
foreach ($timetables as $timetable) {
- $adminNames[$timetable['store_id']][] = [
+ $storeId = $timetable['store_id'];
-
++
+ if (!isset($adminNames[$storeId])) {
+ $adminNames[$storeId] = [];
+ }
+
+ // Один администратор может работать в несколько смен в один день
+ $adminNames[$storeId][] = [
'id' => $timetable['admin_id'],
'name' => $timetable['adminName'],
'shift_id' => $timetable['shift_id'],
$storeSaleReturnTotal += (int)$storeSale['total'];
}
-
+ // Добавляем админов из продаж, которые отсутствуют в $adminNames
+ if (!isset($adminNames[$store->id])) {
+ $adminNames[$store->id] = [];
+ }
-
++
+ // Собираем уникальные admin_id из продаж
+ $salesAdminIds = [];
+ foreach ($storeSaleArr as $sale) {
+ $salesAdminIds[$sale['admin_id']] = true;
+ }
+ foreach ($storeSaleReturnArr as $sale) {
+ $salesAdminIds[$sale['admin_id']] = true;
+ }
+
+ // Определяем админов из продаж, которых нет в смене
+ $missingAdminIds = [];
+ foreach ($salesAdminIds as $adminId => $_) {
+ $adminExists = false;
+ foreach ($adminNames[$store->id] as $admin) {
+ if ($admin['id'] == $adminId) {
+ $adminExists = true;
+ break;
+ }
+ }
+ if (!$adminExists) {
+ $missingAdminIds[] = $adminId;
+ }
+ }
-
++
+ // Batch-загрузка имен отсутствующих админов одним запросом
+ if (!empty($missingAdminIds)) {
+ $missingAdmins = Admin::find()
+ ->select(['id', 'name'])
+ ->where(['id' => $missingAdminIds])
+ ->indexBy('id')
+ ->asArray()
+ ->all();
++
+ foreach ($missingAdminIds as $adminId) {
+ $adminNames[$store->id][] = [
+ 'id' => $adminId,
+ 'name' => $missingAdmins[$adminId]['name'] ?? 'Unknown',
+ 'shift_id' => 0, // У админов из продаж нет shift_id
+ ];
+ }
+ }
+
$storeVisitorsQuantityTotal += $storeVisitorsQuantity;
$storeSaleQuantityTotal += $storeSaleQuantity;
$storeSaleTotalTotal += $storeSaleTotal;
$store_guids[$store_id] = $eitStores[$store_id]['export_val'];
}
+ // Получаем все уникальные admin_id сотрудников за период из фактических смен
$cond = ['or'];
foreach ($data->date as $ind => $dateStartEnd) {
- $cond[]= ['between', 'date',
- date("Y-m-d 00:00:00", strtotime($dateStartEnd[0])),
- date("Y-m-d 23:59:59", strtotime($dateStartEnd[1]))];
+ $cond[] = ['between', 'date',
+ date("Y-m-d", strtotime($dateStartEnd[0])),
+ date("Y-m-d", strtotime($dateStartEnd[1]))];
}
-
- $employeesTotal = Sales::find()->select(["COUNT(*) as cnt", "admin_id"]) // , "DATA_FORMAT(date, '%Y-%m-%d') as day"
++
+ $allAdminsInPeriod = TimetableFactModel::find()
+ ->select(['admin_id'])
+ ->distinct()
->where(['store_id' => $data->stores])
->andWhere($cond)
- ->groupBy(['admin_id'])->asArray()->all();
- $employeeCountTotal = count($employeesTotal);
+ ->andWhere(['>', 'work_time', 0])
+ ->asArray()
+ ->all();
- // Получаем все уникальные admin_id сотрудников за период
- $adminIdsInPeriod = ArrayHelper::getColumn($employeesTotal, 'admin_id');
+ $adminIdsInPeriod = ArrayHelper::getColumn($allAdminsInPeriod, 'admin_id');
+ $employeeCountTotal = count($adminIdsInPeriod);
$positionMap = $this->buildPositionMap($adminIdsInPeriod);
$adminSkillMap = $this->buildAdminSkillMap($adminIdsInPeriod);
$employeeCount = [];
$weekEmployees = []; // Собираем сотрудников за неделю
$storeWeekEmployees = []; // Сотрудники по магазинам за неделю
-
++
+ // Получаем сотрудников из фактических смен за неделю
foreach ($data->stores as $store_id) {
- $employees = Sales::find()->select(["COUNT(*) as cnt", "admin_id"])
- ->where(['between', 'date',
- date("Y-m-d 00:00:00", strtotime($dateStartEnd[0])),
- date("Y-m-d 23:59:59", strtotime($dateStartEnd[1]))])
- ->andWhere(['store_id' => $store_id])
- ->groupBy(['admin_id'])->asArray()->all();
+ $employees = TimetableFactModel::find()
+ ->select(['admin_id'])
+ ->distinct()
+ ->where(['store_id' => $store_id])
+ ->andWhere(['>=', 'date', date("Y-m-d", strtotime($dateStartEnd[0]))])
+ ->andWhere(['<=', 'date', date("Y-m-d", strtotime($dateStartEnd[1]))])
+ ->andWhere(['>', 'work_time', 0])
+ ->asArray()
+ ->all();
-
++
$employeeCount[$store_id] = count($employees);
// Сохраняем сотрудников для этого магазина
$employeeCount = [];
$allDayEmployees = []; // Собираем всех сотрудников за день по всем магазинам
$storeEmployeesData = []; // Данные о сотрудниках по магазинам
-
++
+ // Получаем сотрудников из фактических смен за день
foreach ($data->stores as $store_id) {
- $employees = Sales::find()->select(["COUNT(*) as cnt", "admin_id"])
- ->where([
- 'between',
- 'date',
- date("Y-m-d 00:00:00", strtotime($day)),
- date("Y-m-d 23:59:59", strtotime($day))
- ])
- ->andWhere(['store_id' => $store_id])
- ->groupBy(['admin_id'])->asArray()->all();
+ $employees = TimetableFactModel::find()
+ ->select(['admin_id'])
+ ->distinct()
+ ->where(['store_id' => $store_id])
+ ->andWhere(['date' => $day])
+ ->andWhere(['>', 'work_time', 0])
+ ->asArray()
+ ->all();
-
++
$employeeCount[$store_id] = count($employees);
// Сохраняем данные сотрудников для этого магазина