$modelPosition = DynamicModel::validateData(['position_id' => null, 'action' => 'updatePosition'], [['position_id', 'integer'], ['action', 'string']]);
if ($modelPosition->load(Yii::$app->request->post()) && $modelPosition->action == 'updatePosition') {
- $positionStatus = EmployeePositionStatus::findOne(['admin_id' => $admin_id]);
- if (!$positionStatus) {
- $positionStatus = new EmployeePositionStatus();
- $positionStatus->admin_id = $admin_id;
- $positionStatus->created_at = date('Y-m-d H:i:s');
+ // Гибридный подход: обновляем основное поле (источник истины)
+ $admin->employee_position_id = $modelPosition->position_id;
+
+ // Сохраняем Admin, что автоматически вызовет afterSave
+ // и создаст запись в EmployeePositionStatus для истории
+ if ($admin->save(false)) {
+ Yii::$app->session->setFlash('success', 'Грейд успешно сохранён');
+ } else {
+ Yii::$app->session->setFlash('error', 'Ошибка при сохранении грейда');
}
- $positionStatus->position_id = $modelPosition->position_id;
- $positionStatus->save(false);
+ return $this->controller->redirect(['/grade/update', 'admin_id' => $admin_id]);
} else {
- $modelPosition->position_id = $admin->position ? $admin->position->id : null;
+ // Показываем текущий грейд из основного поля (источник истины)
+ $modelPosition->position_id = $admin->employee_position_id;
$modelPosition->action = 'updatePosition';
$modelPosition->validate();
}
$skills = EmployeeSkill::find()->all();
$skillStatuses = ArrayHelper::map(EmployeeSkillStatus::find()->where(['admin_id' => $admin_id])->all(), 'skill_id', 'created_at');
- $nextPosition = EmployeePosition::findOne(EmployeePosition::findOne($modelPosition->position_id)->next_position_id ?? null) ?? null;
+
+ // Получаем следующую должность на основе текущего грейда
+ $nextPosition = null;
$requiredSkills = [];
- if (isset($nextPosition)) {
- $requiredSkills = $nextPosition->skills;
+ $currentPosition = EmployeePosition::findOne($modelPosition->position_id);
+ if ($currentPosition && $currentPosition->next_position_id) {
+ $nextPosition = EmployeePosition::findOne($currentPosition->next_position_id);
+ if ($nextPosition) {
+ $requiredSkills = $nextPosition->skills;
+ }
}
return $this->controller->render('/grade/update',
/**
* После сохранения проверяем, изменилась ли должность, и создаем запись EmployeePayment
+ * А также синхронизируем историю в EmployeePositionStatus (гибридный подход)
*/
public function afterSave($insert, $changedAttributes)
{
$oldPositionId = $changedAttributes['employee_position_id'] ?? null;
$newPositionId = $this->employee_position_id;
+ // === ГИБРИДНЫЙ ПОДХОД: Ведение истории в EmployeePositionStatus ===
+ if ($newPositionId && $oldPositionId != $newPositionId) {
+ try {
+ // Закрыть предыдущую должность, если была
+ if ($oldPositionId) {
+ EmployeePositionStatus::updateAll(
+ ['closed_at' => date('Y-m-d H:i:s')],
+ ['admin_id' => $this->id, 'closed_at' => null]
+ );
+ }
+
+ // Создать новую запись об истории
+ $positionStatus = new EmployeePositionStatus();
+ $positionStatus->admin_id = $this->id;
+ $positionStatus->position_id = $newPositionId;
+ $positionStatus->created_at = date('Y-m-d H:i:s');
+ $positionStatus->save(false);
+
+ Yii::info("История грейда обновлена для admin_id={$this->id}, position_id={$newPositionId}", 'grade-sync');
+ } catch (\Exception $e) {
+ Yii::error("Ошибка при обновлении истории EmployeePositionStatus для admin_id={$this->id}: " . $e->getMessage(), 'grade-sync');
+ // Не бросаем исключение, чтобы не прервать сохранение Admin
+ }
+ }
+
+ // === СИНХРОНИЗАЦИЯ ЗАРПЛАТЫ ===
// Если должность была добавлена или изменена, и сотрудник не уволен
if ($newPositionId && ($oldPositionId != $newPositionId || $insert) && $this->group_id != AdminGroup::GROUP_FIRED) {
try {
<div class="row">
<div class="col">
- Присвоение грейда и скиллов: <?= $admin->name ?>
+ <h5>Присвоение грейда и скиллов: <strong><?= $admin->name ?></strong></h5>
+ </div>
+</div>
+
+<!-- Информация о текущем грейде -->
+<div class="row mb-3 mt-2">
+ <div class="col">
+ <div class="alert alert-info" role="alert">
+ <?php
+ $currentPosition = $admin->employeePosition;
+ if ($currentPosition):
+ ?>
+ <strong>Текущий грейд:</strong> <?= Html::encode($currentPosition->name) ?>
+ <br><small>Установлен с: <?= $currentPosition->created_at ?? 'дата неизвестна' ?></small>
+ <?php else: ?>
+ <strong style="color: #dc3545;">⚠️ Грейд не установлен</strong>
+ <br><small>Пожалуйста, выберите грейд из списка ниже</small>
+ <?php endif; ?>
+ </div>
</div>
</div>
<?php Pjax::begin(['id' => 'some_pjax_id']) ?>
<?php $gradeForm = ActiveForm::begin(['id' => 'grade-form']); ?>
- <div class="row mt-2 mb-2">
- <div class="col-1 mt-2 text-right">
- Позиция:
+ <div class="row mt-2 mb-3">
+ <div class="col-3">
+ <label class="font-weight-bold">Назначить грейд:</label>
</div>
- <div class="col-2">
+ </div>
+ <div class="row mb-3">
+ <div class="col-4">
<?= $gradeForm->field($modelPosition, 'position_id')->dropDownList(
- ArrayHelper::map($positions, 'id', 'name'))->label(false); ?>
+ ['' => '-- Выберите грейд --'] + ArrayHelper::map($positions, 'id', 'name'),
+ ['class' => 'form-control']
+ )->label(false); ?>
</div>
- <div class="col-2 mt-1">
- <?= Html::submitButton('Сохранить', ['class' => 'btn btn-primary'])?>
+ <div class="col-2">
+ <?= Html::submitButton('💾 Сохранить грейд', ['class' => 'btn btn-primary'])?>
</div>
<div class="col-2">
<?= $gradeForm->field($modelPosition, 'action')->hiddenInput()->label(false) ?>
<?php ActiveForm::end(); ?>
<?php endforeach; ?>
+<!-- История назначений грейда -->
+<div class="row mt-5 mb-3">
+ <div class="col-12">
+ <h6 class="font-weight-bold">📋 История назначений грейда</h6>
+ </div>
+</div>
+
+<?php
+$positionHistory = \yii_app\records\EmployeePositionStatus::find()
+ ->where(['admin_id' => $admin->id])
+ ->orderBy(['created_at' => SORT_DESC])
+ ->with('employeePosition')
+ ->all();
+
+if (!empty($positionHistory)):
+?>
+ <div class="row">
+ <div class="col-12">
+ <table class="table table-sm table-bordered">
+ <thead class="table-light">
+ <tr>
+ <th style="width: 40%">Должность</th>
+ <th style="width: 30%">Начало</th>
+ <th style="width: 30%">Окончание</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($positionHistory as $history): ?>
+ <tr>
+ <td>
+ <?php if ($history->position_id): ?>
+ <?= Html::encode(\yii_app\records\EmployeePosition::findOne($history->position_id)->name ?? 'Должность удалена') ?>
+ <?php else: ?>
+ <em>—</em>
+ <?php endif; ?>
+ </td>
+ <td>
+ <?= Yii::$app->formatter->asDatetime($history->created_at, 'php:d.m.Y H:i') ?>
+ </td>
+ <td>
+ <?php if ($history->closed_at): ?>
+ <?= Yii::$app->formatter->asDatetime($history->closed_at, 'php:d.m.Y H:i') ?>
+ <?php else: ?>
+ <span class="badge bg-success">Активный</span>
+ <?php endif; ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+ </div>
+ </div>
+<?php else: ?>
+ <div class="row">
+ <div class="col-12">
+ <p class="text-muted"><em>История назначений грейда отсутствует</em></p>
+ </div>
+ </div>
+<?php endif; ?>
+
<?php Pjax::end() ?>
</div>