]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Добавление позиции в грейдах и синхронизация со статусом
authorVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Tue, 11 Nov 2025 08:36:28 +0000 (11:36 +0300)
committerVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Tue, 11 Nov 2025 08:36:28 +0000 (11:36 +0300)
erp24/actions/grade/UpdateAction.php
erp24/records/Admin.php
erp24/views/grade/update.php

index 1a74255842b7abdea3402b5d9fbdf68ce7b59bcb..abd85ac0f80d74e1ae21b71c3fb10069d98e023c 100755 (executable)
@@ -24,16 +24,20 @@ class UpdateAction extends Action
         $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();
         }
@@ -55,10 +59,16 @@ class UpdateAction extends Action
 
         $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',
index 65f295a0248789282efbbe14d99237e2b406dbca..157cc93199ac6e4a0f6112ae12514f4656849d0c 100755 (executable)
@@ -769,6 +769,7 @@ class Admin extends ActiveRecord implements IdentityInterface
 
     /**
      * После сохранения проверяем, изменилась ли должность, и создаем запись EmployeePayment
+     * А также синхронизируем историю в EmployeePositionStatus (гибридный подход)
      */
     public function afterSave($insert, $changedAttributes)
     {
@@ -779,6 +780,32 @@ class Admin extends ActiveRecord implements IdentityInterface
             $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 {
index 5f58c7c430a3668eadcd781cd79429324e99d76f..1ed05cae16aa73a392c46c80fdff902a0fe853bb 100755 (executable)
@@ -33,23 +33,45 @@ use dosamigos\datetimepicker\DateTimePicker;
 
 <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) ?>
@@ -120,6 +142,66 @@ use dosamigos\datetimepicker\DateTimePicker;
     <?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>