From 7230b4e1a48e1fbcc6c1c34ed3171e031934e543 Mon Sep 17 00:00:00 2001 From: Aleksey Filippov Date: Mon, 26 Jan 2026 10:58:45 +0300 Subject: [PATCH] =?utf8?q?[ERP-40]=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?utf8?q?=D0=B8=D0=B5=20=D0=B8=D1=81=D1=82=D0=BE=D1=80=D0=B8=D0=B8=20?= =?utf8?q?=D0=BA=D0=B0=D1=82=D0=B0=D0=BB=D0=BE=D0=B3=D0=B0=20=D0=B8=20?= =?utf8?q?=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D0=BD=D1=82=D0=BA=D0=B8=20=D1=84?= =?utf8?q?=D0=BE=D0=BA=D1=83=D1=81=D0=BD=D1=8B=D1=85=20=D0=B3=D1=80=D1=83?= =?utf8?q?=D0=BF=D0=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../Products1cClassDynamicController.php | 28 +++++++++++-------- erp24/config/db.php | 2 +- erp24/records/Products1cClassDynamic.php | 15 ++++++---- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/erp24/commands/Products1cClassDynamicController.php b/erp24/commands/Products1cClassDynamicController.php index bed4400c..ff1f6bd2 100644 --- a/erp24/commands/Products1cClassDynamicController.php +++ b/erp24/commands/Products1cClassDynamicController.php @@ -203,14 +203,18 @@ class Products1cClassDynamicController extends Controller $transaction = Yii::$app->db->beginTransaction(Transaction::SERIALIZABLE); try { - // SELECT FOR UPDATE: блокируем строку, перечитываем актуальные данные - $activeRecord = Products1cClassDynamic::find() - ->where([ - 'product_id' => $productData['product_id'], - 'active' => Products1cClassDynamic::ACTIVE, - ]) - ->forUpdate() - ->one(); + // SELECT FOR UPDATE через raw SQL (Yii2 не имеет встроенного forUpdate()) + // Блокируем строку до конца транзакции + $sql = "SELECT id FROM {{%products_1c_class_dynamic}} + WHERE product_id = :product_id AND active = :active + FOR UPDATE"; + $lockedRow = Yii::$app->db->createCommand($sql, [ + ':product_id' => $productData['product_id'], + ':active' => Products1cClassDynamic::ACTIVE, + ])->queryOne(); + + // Получаем ActiveRecord по заблокированному ID + $activeRecord = $lockedRow ? Products1cClassDynamic::findOne($lockedRow['id']) : null; // Проверяем, не обработал ли кто-то эту запись параллельно if ($activeRecord === null) { @@ -230,14 +234,14 @@ class Products1cClassDynamicController extends Controller // Определяем какие поля изменились $changes = $activeRecord->detectChanges($productData); - // Закрываем старую запись - $activeRecord->disableRecord(); + // Закрываем старую запись С указанием причины (changes) + $activeRecord->disableRecord($changes); if (!$activeRecord->save()) { throw new \Exception('Ошибка закрытия записи: ' . implode(', ', $activeRecord->getFirstErrors())); } - // Создаём новую запись с указанием изменённых полей - $newRecord = Products1cClassDynamic::createFromData($productData, $changes); + // Создаём новую запись БЕЗ changes (это текущее актуальное состояние) + $newRecord = Products1cClassDynamic::createFromData($productData, null); if (!$newRecord->save()) { throw new \Exception('Ошибка создания записи: ' . implode(', ', $newRecord->getFirstErrors())); } diff --git a/erp24/config/db.php b/erp24/config/db.php index d3f6e658..86ca03c4 100644 --- a/erp24/config/db.php +++ b/erp24/config/db.php @@ -15,7 +15,7 @@ return 1 == 1 ? [ 'defaultSchema' => 'erp24' //specify your schema here, public is the default schema ] ], -// 'on afterOpen' => function($event) { $event->sender->createCommand("SET search_path TO public, erp24;")->execute(); }, + 'on afterOpen' => function($event) { $event->sender->createCommand("SET search_path TO erp24, public;")->execute(); }, // PostgreSQL 'charset' => 'utf8', 'enableSchemaCache' => true, diff --git a/erp24/records/Products1cClassDynamic.php b/erp24/records/Products1cClassDynamic.php index ddb4d9c9..db5785b1 100644 --- a/erp24/records/Products1cClassDynamic.php +++ b/erp24/records/Products1cClassDynamic.php @@ -153,18 +153,21 @@ class Products1cClassDynamic extends \yii\db\ActiveRecord } /** - * Закрытие текущей активной записи - * - * Устанавливает: - * - date_to = текущая дата - * - active = 0 + * Закрытие записи (деактивация) * + * @param array|null $changes Список изменённых полей, из-за которых закрывается запись * @return self */ - public function disableRecord(): self + public function disableRecord(?array $changes = null): self { $this->date_to = date('Y-m-d'); $this->active = self::NOT_ACTIVE; + $this->updated_at = date('Y-m-d H:i:s'); + + // changes записывается в закрываемую запись — причина закрытия + if ($changes !== null) { + $this->changes = json_encode($changes, JSON_UNESCAPED_UNICODE); + } return $this; } -- 2.39.5