]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Правки по MR
authorVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Wed, 3 Dec 2025 12:12:17 +0000 (15:12 +0300)
committerVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Wed, 3 Dec 2025 12:12:17 +0000 (15:12 +0300)
erp24/records/Admin.php

index 28a99f79cbeb5b52c8a748e7e197532b7c6e1bfd..513cf91d2f803293499517236cd6e24847bc32c5 100755 (executable)
@@ -768,63 +768,88 @@ class Admin extends ActiveRecord implements IdentityInterface
     }
 
     /**
-     * После сохранения проверяем, изменилась ли должность, и создаем запись EmployeePayment
-     * А также синхронизируем историю в EmployeePositionStatus (гибридный подход)
+     * Обработка после сохранения записи сотрудника (Admin)
+     * 
+     * Метод выполняет две критически важные автоматические синхронизации:
+     * 
+     * 1. **ИСТОРИЯ ГРЕЙДОВ (EmployeePositionStatus)** - Гибридный подход
+     *    - Отслеживает изменения должности сотрудника во времени
+     *    - При изменении employee_position_id:
+     *      a) Закрывает все активные записи истории (closed_at = NOW)
+     *      b) Создаёт новую запись с текущей должностью (closed_at = NULL)
+     *    - Важно: история НЕ создаётся при первом сохранении нового сотрудника,
+     *      так как нет предыдущей позиции для закрытия
+     * 
+     * 2. **СИНХРОНИЗАЦИЯ ЗАРПЛАТЫ (EmployeePayment)**
+     *    - Автоматически создаёт запись о зарплате через SalarySyncService
+     *    - Срабатывает когда:
+     *      a) Установлена должность (employee_position_id не NULL)
+     *      b) Должность изменилась ИЛИ создаётся новая запись ($insert)
+     *      c) Сотрудник не уволен (group_id != AdminGroup::GROUP_FIRED)
+     *    - В отличие от истории грейдов, работает и для новых записей
+     * 
+     * **Обработка ошибок:**
+     * - Все операции обёрнуты в try-catch
+     * - Ошибки логируются, но НЕ прерывают сохранение Admin
+     * - Это гарантирует, что основная операция (сохранение сотрудника) всегда завершится
+     * 
+     * **Логирование:**
+     * - История грейдов: категория 'grade-sync'
+     * - Синхронизация зарплаты: категория 'salary-sync'
+     * 
+     * @param bool $insert Флаг вставки новой записи (true) или обновления (false)
+     * @param array $changedAttributes Массив изменённых атрибутов в формате ['attribute' => 'oldValue']
+     * @return void
+     * 
+     * @see EmployeePositionStatus Модель для истории должностей
+     * @see SalarySyncService Сервис синхронизации зарплаты
+     * @see EmployeePayment Модель зарплатных данных
      */
     public function afterSave($insert, $changedAttributes)
     {
         parent::afterSave($insert, $changedAttributes);
 
-        // Проверяем, изменилось ли поле employee_position_id
-        // Важно: проверяем как через changedAttributes, так и через сравнение значений
+        // Создаём историю только если должность реально изменилась и новая должность установлена
         $oldPositionId = $changedAttributes['employee_position_id'] ?? null;
         $newPositionId = $this->employee_position_id;
         
-        // Если это новая запись или изменилось employee_position_id
-        if ($insert || ($oldPositionId != $newPositionId && array_key_exists('employee_position_id', $changedAttributes))) {
-            // === ГИБРИДНЫЙ ПОДХОД: Ведение истории в EmployeePositionStatus ===
-            if ($newPositionId && $oldPositionId != $newPositionId) {
-                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(false)) {
-                        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
+        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
             }
         }
 
-        // === СИНХРОНИЗАЦИЯ ЗАРПЛАТЫ ===
-        // Если должность была добавлена или изменена, и сотрудник не уволен
-        $oldPositionIdForSalary = $changedAttributes['employee_position_id'] ?? null;
-        $newPositionIdForSalary = $this->employee_position_id;
-        if ($newPositionIdForSalary && ($oldPositionIdForSalary != $newPositionIdForSalary || $insert) && $this->group_id != AdminGroup::GROUP_FIRED) {
+        if ($newPositionId && ($oldPositionId != $newPositionId || $insert) && $this->group_id != AdminGroup::GROUP_FIRED) {
             try {
                 $syncService = new SalarySyncService();
                 $result = $syncService->createPaymentFromPosition($this->id);
                 
                 if ($result) {
-                    Yii::info("Автоматически создана запись EmployeePayment для admin_id={$this->id}, position_id={$newPositionIdForSalary}", 'salary-sync');
+                    Yii::info("Автоматически создана запись EmployeePayment для admin_id={$this->id}, position_id={$newPositionId}", 'salary-sync');
                 }
             } catch (\Exception $e) {
                 Yii::error("Ошибка автоматической синхронизации оклада для admin_id={$this->id}: " . $e->getMessage(), 'salary-sync');