]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Деактивация и мягкое удаление
authorVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Mon, 8 Sep 2025 09:13:49 +0000 (12:13 +0300)
committerVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Mon, 8 Sep 2025 09:13:49 +0000 (12:13 +0300)
erp24/controllers/MatrixTypeController.php
erp24/migrations/m250905_090045_add_parentid_active_fields_to_matrix_type_table.php
erp24/records/MatrixType.php
erp24/records/MatrixTypeSearch.php
erp24/views/matrix-type/index.php
erp24/web/js/matrix-type/index.js

index c1ebd6295fe84be1daecee233bf7f7ef2515bf36..9d346ce64d1a52f2bb5d678cbad0f0f71e5eedce 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace app\controllers;
 
+use Throwable;
 use Yii;
 use yii_app\records\MatrixType;
 use yii\data\ActiveDataProvider;
@@ -123,20 +124,54 @@ class MatrixTypeController extends Controller
     public function actionToggleActive()
     {
         Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
-        $id = Yii::$app->request->post('id');
-        $active = Yii::$app->request->post('active');
+        $id = (int) Yii::$app->request->post('id');
+        $active = (int) Yii::$app->request->post('active');
 
         $model = $this->findModel($id);
         if (!$model) {
             return ['success' => false, 'message' => 'Не найдено'];
         }
 
-        $model->active = (int)$active;
-        if ($model->save(false)) {
+        $db = Yii::$app->db;
+        $transaction = $db->beginTransaction();
+
+        try {
+            $model->active = $active;
+            if (!$model->save(false)) {
+                throw new \RuntimeException('Не удалось сохранить узел');
+            }
+
+            if ($active === 0 && empty($model->parent_id)) {
+                $this->deactivateChildren($model);
+            }
+
+            $transaction->commit();
             return ['success' => true];
+
+        } catch (Throwable $e) {
+            $transaction->rollBack();
+            Yii::error($e->getMessage(), 'matrix-type.toggle-active');
+            return ['success' => false, 'message' => 'Ошибка при сохранении'];
+        }
+    }
+
+    protected function deactivateChildren(MatrixType $parent): void
+    {
+        $children = MatrixType::find()
+            ->where(['parent_id' => $parent->id])
+            ->all();
+
+        foreach ($children as $child) {
+            if ($child->active != 0) {
+                $child->active = 0;
+                if(!$child->save()) {
+                    Yii::error("Ошибка сохранения " . json_encode($child->getErrors(), JSON_UNESCAPED_UNICODE));
+                }
+            }
+            $this->deactivateChildren($child);
         }
-        return ['success' => false, 'message' => 'Не удалось сохранить'];
     }
+
     /**
      * Deletes an existing MatrixType model.
      * If deletion is successful, the browser will be redirected to the 'index' page.
@@ -163,6 +198,63 @@ class MatrixTypeController extends Controller
         $model->delete();
     }
 
+    public function actionSoftDelete($id)
+    {
+        $model = $this->findModel($id);
+        if (!$model) {
+            return $this->redirect(['index']);
+        }
+
+        $db = Yii::$app->db;
+        $transaction = $db->beginTransaction();
+
+        try {
+            $now = date('Y-m-d H:i:s');
+            $uid = Yii::$app->user->id ?? null;
+
+            $this->markDeleted($model, $uid, $now);
+
+            if (empty($model->parent_id)) {
+                $this->markDeletedChildren($model, $uid, $now);
+            }
+
+            $transaction->commit();
+            return $this->redirect(['index']);
+        } catch (\Throwable $e) {
+            $transaction->rollBack();
+            Yii::error($e->getMessage(), 'matrix-type.soft-delete');
+            return $this->redirect(['index']);
+        }
+    }
+
+    protected function markDeleted(MatrixType $matrixType, $uid, $now): void
+    {
+        if (!empty($matrixType->deleted_at)) return;
+
+        $result = $matrixType->updateAttributes([
+            'deleted_by' => $uid,
+            'deleted_at' => $now,
+            'active'     => 0,
+        ]);
+        if ($result === false) {
+            Yii::error("Ошибка сохранения " . json_encode($matrixType->getErrors(), JSON_UNESCAPED_UNICODE));
+            throw new \RuntimeException("Не удалось пометить удалённым ID={$matrixType->id}");
+        }
+    }
+
+    protected function markDeletedChildren(MatrixType $parent, $uid, $now): void
+    {
+        $children = MatrixType::find()
+            ->where(['parent_id' => $parent->id])
+            ->all();
+
+        foreach ($children as $child) {
+            $this->markDeleted($child, $uid, $now);
+            $this->markDeletedChildren($child, $uid, $now);
+        }
+    }
+
+
     /**
      * Finds the MatrixType model based on its primary key value.
      * @param int $id
@@ -171,7 +263,7 @@ class MatrixTypeController extends Controller
      */
     protected function findModel($id)
     {
-        if (($model = MatrixType::findOne($id)) !== null) {
+        if (($model = MatrixType::find()->where(['id' => $id])->andWhere(['deleted_at' => null])->one()) !== null) {
             return $model;
         }
 
index e2b70c18243201abdd408b0239cebb5cc4910f9a..08db8437e39e01422a13005d4d452c389a89818d 100644 (file)
@@ -29,6 +29,20 @@ class m250905_090045_add_parentid_active_fields_to_matrix_type_table extends Mig
                 $this->tinyInteger()->notNull()->defaultValue(1)->comment('активность')
             );
         }
+        if (!$this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('deleted_by')) {
+            $this->addColumn(
+                self::TABLE_NAME,
+                'deleted_by',
+                $this->integer()->null()->comment('Кем удалено - id пользователя')
+            );
+        }
+        if (!$this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('deleted_at')) {
+            $this->addColumn(
+                self::TABLE_NAME,
+                'deleted_at',
+                $this->timestamp()->defaultValue(null)->comment('дата удаления')
+            );
+        }
     }
 
     /**
@@ -42,6 +56,12 @@ class m250905_090045_add_parentid_active_fields_to_matrix_type_table extends Mig
         if ($this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('active')) {
             $this->dropColumn(self::TABLE_NAME, 'active');
         }
+        if ($this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('deleted_by')) {
+            $this->dropColumn(self::TABLE_NAME, 'deleted_by');
+        }
+        if ($this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('deleted_at')) {
+            $this->dropColumn(self::TABLE_NAME, 'deleted_at');
+        }
     }
 
     /*
index 2904ff1811229804238cd704ac50701919037f7a..c0d46ff3fa5985d1bc9dad171ee8f35cc6e308b6 100644 (file)
@@ -61,17 +61,10 @@ class MatrixType extends \yii\db\ActiveRecord
                 ['name', 'parent_id'],
                 'unique',
                 'targetAttribute' => ['name', 'parent_id'],
-                'message' => 'Ð\9fодгруппа с таким названием уже существует в этой группе.',
+                'message' => 'Ð\93руппа с таким названием уже существует в этой группе.',
             ],
 
-            // Уникальность имени для групп (без parent_id)
-            [
-                'name',
-                'unique',
-                'targetAttribute' => 'name',
-                'filter' => ['parent_id' => null],
-                'message' => 'Группа с таким названием уже существует.',
-            ],
+
         ];
     }
 
index 0aaffb53136af0701ed88a8587642617d77a4d4e..a4fe7421d5b3d5a62a3af7bf3c522c4818501876 100644 (file)
@@ -20,7 +20,10 @@ class MatrixTypeSearch extends MatrixType
     {
         $this->load($params, '');
 
-        $allTypes = MatrixType::find()->orderBy(['parent_id' => SORT_ASC, 'id' => SORT_ASC])->all();
+        $allTypes = MatrixType::find()
+            ->andWhere(['deleted_at' => null])
+            ->orderBy(['parent_id' => SORT_ASC, 'id' => SORT_ASC])
+            ->all();
 
         if ($this->active === '' || $this->active === null) {
             return new ArrayDataProvider(['allModels' => $allTypes, 'pagination' => false, 'sort' => false]);
index 0eba894030283853ef4bcd9f678e025df17429c4..49bfa268bdeb650f929e44e64f2505c763c17939 100644 (file)
@@ -193,6 +193,7 @@ $this->registerJsFile('/js/matrix-type/index.js', ['position' => \yii\web\View::
                         [
                             'class' => 'js-toggle-active',
                             'data-id' => $model->id,
+                            'data-parent' => $model->parent_id ?? '',
                         ]
                     );
                 },
@@ -204,7 +205,7 @@ $this->registerJsFile('/js/matrix-type/index.js', ['position' => \yii\web\View::
                 'contentOptions' => ['class' => 'text-center', 'style' => 'width:80px;  min-width:50px;  '],
                 'urlCreator' => function ($action, $model, $key, $index) {
                     if ($action === 'delete') {
-                        return Url::to(['delete', 'id' => $model->id]);
+                        return Url::to(['soft-delete', 'id' => $model->id]);
                     }
                     return '#';
                 },
index 62036bd8363bc62d70f2b8d06ea6244a70544072..ec2408e0a8d26ccb730c1ebf82c2d5fad1c8d112 100644 (file)
                 _csrf: yii.getCsrfToken()
             },
             success: function (res) {
-                if (!res.success) {
-                    alert('Ошибка: ' + res.message);
+                if (!res || res.success !== true) {
+                    alert('Ошибка: ' + (res && res.message ? res.message : 'Не удалось сохранить'));
                     checkbox.prop('checked', !active);
+                    return;
+                }
+
+                if (active === 0 && checkbox.closest('tr').find('td:first').text().trim() !== '') {
+                    var nodeId = id;
+                    $('.js-toggle-active[data-parent="' + nodeId + '"]').each(function () {
+                        $(this).prop('checked', false);
+                    });
                 }
             },
             error: function () {