]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Удаляем afterSave из Admin.php и переносим логику истории грейда в метод origin/fix_fomichev_erp-497_remove_salary_sync
authorVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Wed, 17 Dec 2025 10:22:27 +0000 (13:22 +0300)
committerVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Wed, 17 Dec 2025 10:22:27 +0000 (13:22 +0300)
erp24/actions/grade/AdminUpdateAction.php
erp24/actions/grade/UpdateAction.php
erp24/records/Admin.php
erp24/records/EmployeePositionStatus.php

index ada50c09129689a28752093685e8a1de5184b5c5..34d1a1d40a6513a91de2907013f031874a8bb84f 100644 (file)
@@ -12,6 +12,7 @@ use yii_app\records\AdminStores;
 use yii_app\records\CityStore;
 use yii_app\records\Companies;
 use yii_app\records\EmployeePosition;
+use yii_app\records\EmployeePositionStatus;
 use yii_app\records\ExportImportTable;
 use yii_app\services\HistoryService;
 
@@ -144,8 +145,17 @@ class AdminUpdateAction extends Action
                 }
 
                 if (!$raiseError) {
+                    // Сохраняем старое значение employee_position_id для отслеживания изменений
+                    $oldEmployeePositionId = $model->getOldAttribute('employee_position_id');
+                    
                     if ($model->save(false)) {
                         HistoryService::setHistoryUserInfo($model);
+                        
+                        // Создаём историю грейда если employee_position_id изменился
+                        $newEmployeePositionId = $model->employee_position_id;
+                        if ($newEmployeePositionId && $oldEmployeePositionId != $newEmployeePositionId) {
+                            EmployeePositionStatus::updateHistory($model->id, $oldEmployeePositionId, $newEmployeePositionId);
+                        }
 
                         AdminStores::deleteAll(['admin_id' => $model->id]);
 
index 2e091236c284c9c87592996ac1a1bb1775b7e2e7..af5ff3764ff9fe0681f2ee1ffdc998a810f08440 100755 (executable)
@@ -96,9 +96,13 @@ class UpdateAction extends Action
                 }
             }
             
-            // Сохраняем Admin, что автоматически вызовет afterSave 
-            // и создаст запись в EmployeePositionStatus для истории
+            // Сохраняем Admin и создаём историю грейда
             if ($admin->save(false)) {
+                // Создаём историю только если должность реально изменилась и новая должность установлена
+                if ($modelPosition->position_id && $oldPositionId != $modelPosition->position_id) {
+                    EmployeePositionStatus::updateHistory($admin->id, $oldPositionId, $modelPosition->position_id);
+                }
+                
                 if ($oldPositionId == $modelPosition->position_id) {
                     // Если ничего не изменилось - показываем стандартное сообщение
                     Yii::$app->session->setFlash('success', 'Данные успешно сохранены');
index c0e39f83231141d17ba26c20104d19ebde7eecc0..42d5651bf5093b6902402b50189cce043d1e7c43 100755 (executable)
@@ -766,71 +766,4 @@ class Admin extends ActiveRecord implements IdentityInterface
         return false;
     }
 
-    /**
-     * Обработка после сохранения записи сотрудника (Admin)
-     * 
-     * Метод выполняет две критически важные автоматические синхронизации:
-     * 
-     * 1. **ИСТОРИЯ ГРЕЙДОВ (EmployeePositionStatus)** - Гибридный подход
-     *    - Отслеживает изменения должности сотрудника во времени
-     *    - При изменении employee_position_id:
-     *      a) Закрывает все активные записи истории (closed_at = NOW)
-     *      b) Создаёт новую запись с текущей должностью (closed_at = NULL)
-     *    - Важно: история НЕ создаётся при первом сохранении нового сотрудника,
-     *      так как нет предыдущей позиции для закрытия     *
-     *
-     * **Обработка ошибок:**
-     * - Все операции обёрнуты в try-catch
-     * - Ошибки логируются, но НЕ прерывают сохранение Admin
-     * - Это гарантирует, что основная операция (сохранение сотрудника) всегда завершится
-     * 
-     * **Логирование:**
-     * - История грейдов: категория 'grade-sync'
-     * - Синхронизация зарплаты: категория 'salary-sync'
-     * 
-     * @param bool $insert Флаг вставки новой записи (true) или обновления (false)
-     * @param array $changedAttributes Массив изменённых атрибутов в формате ['attribute' => 'oldValue']
-     * @return void
-     * 
-     * @see EmployeePositionStatus Модель для истории должностей
-     * @see EmployeePayment Модель зарплатных данных
-     */
-    public function afterSave($insert, $changedAttributes)
-    {
-        parent::afterSave($insert, $changedAttributes);
-
-        // Создаём историю только если должность реально изменилась и новая должность установлена
-        $oldPositionId = $changedAttributes['employee_position_id'] ?? null;
-        $newPositionId = $this->employee_position_id;
-        
-        if ($newPositionId && $oldPositionId != $newPositionId && array_key_exists('employee_position_id', $changedAttributes)) {
-            try {
-                // Закрыть ВСЕ активные записи для этого админа (на случай если есть несколько активных)
-                $closedCount = EmployeePositionStatus::updateAll(
-                    ['closed_at' => date('Y-m-d H:i:s')],
-                    ['admin_id' => $this->id, 'closed_at' => null]
-                );
-                
-                Yii::info("Закрыто активных записей для admin_id={$this->id}: {$closedCount}", 'grade-sync');
-                
-                // Создать новую запись об истории (даже если возвращаемся к предыдущей должности)
-                $positionStatus = new EmployeePositionStatus();
-                $positionStatus->admin_id = $this->id;
-                $positionStatus->position_id = $newPositionId;
-                $positionStatus->created_at = date('Y-m-d H:i:s');
-                $positionStatus->closed_at = null; // Явно устанавливаем null для новой активной записи
-                
-                if (!$positionStatus->save()) {
-                    Yii::error("Не удалось сохранить EmployeePositionStatus для admin_id={$this->id}, position_id={$newPositionId}. Ошибки: " . 
-                        implode(', ', $positionStatus->getFirstErrors()), 'grade-sync');
-                } else {
-                    Yii::info("История грейда обновлена для admin_id={$this->id}, position_id={$newPositionId} (старая: " . ($oldPositionId ?? 'null') . ")", 'grade-sync');
-                }
-            } catch (\Exception $e) {
-                Yii::error("Ошибка при обновлении истории EmployeePositionStatus для admin_id={$this->id}: " . $e->getMessage() . 
-                    " Trace: " . $e->getTraceAsString(), 'grade-sync');
-                // Не бросаем исключение, чтобы не прервать сохранение Admin
-            }
-        }
-    }
 }
index 89c44c98fc0715cd3c3788a2a11b6380cf095797..da5655a90b6a78b92a069b3641539b561f3d8ebf 100755 (executable)
@@ -46,4 +46,59 @@ class EmployeePositionStatus extends \yii\db\ActiveRecord
             'closed_at' => 'Closed At',
         ];
     }
+
+    /**
+     * Обновляет историю должностей для сотрудника
+     * 
+     * Метод выполняет следующие операции:
+     * 1. Закрывает все активные записи истории для данного сотрудника (closed_at = NOW)
+     * 2. Создаёт новую запись с новой должностью (closed_at = NULL)
+     * 3. Логирует все операции в категорию 'grade-sync'
+     * 
+     * Метод безопасен - все ошибки логируются, но не прерывают выполнение.
+     * 
+     * @param int $adminId ID администратора/сотрудника
+     * @param int|null $oldPositionId Предыдущая должность (для логирования)
+     * @param int $newPositionId Новая должность
+     * @return bool true в случае успеха, false в случае ошибки
+     */
+    public static function updateHistory($adminId, $oldPositionId, $newPositionId)
+    {
+        // Проверяем, что новая должность действительно указана
+        if (!$newPositionId) {
+            Yii::warning("Попытка обновить историю грейда для admin_id={$adminId} без указания новой должности", 'grade-sync');
+            return false;
+        }
+
+        try {
+            // Закрыть ВСЕ активные записи для этого админа (на случай если есть несколько активных)
+            $closedCount = self::updateAll(
+                ['closed_at' => date('Y-m-d H:i:s')],
+                ['admin_id' => $adminId, 'closed_at' => null]
+            );
+            
+            Yii::info("Закрыто активных записей для admin_id={$adminId}: {$closedCount}", 'grade-sync');
+            
+            // Создать новую запись об истории (даже если возвращаемся к предыдущей должности)
+            $positionStatus = new self();
+            $positionStatus->admin_id = $adminId;
+            $positionStatus->position_id = $newPositionId;
+            $positionStatus->created_at = date('Y-m-d H:i:s');
+            $positionStatus->closed_at = null; // Явно устанавливаем null для новой активной записи
+            
+            if (!$positionStatus->save()) {
+                Yii::error("Не удалось сохранить EmployeePositionStatus для admin_id={$adminId}, position_id={$newPositionId}. Ошибки: " . 
+                    implode(', ', $positionStatus->getFirstErrors()), 'grade-sync');
+                return false;
+            }
+            
+            Yii::info("История грейда обновлена для admin_id={$adminId}, position_id={$newPositionId} (старая: " . ($oldPositionId ?? 'null') . ")", 'grade-sync');
+            return true;
+            
+        } catch (\Exception $e) {
+            Yii::error("Ошибка при обновлении истории EmployeePositionStatus для admin_id={$adminId}: " . $e->getMessage() . 
+                " Trace: " . $e->getTraceAsString(), 'grade-sync');
+            return false;
+        }
+    }
 }