$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) {
// Определяем какие поля изменились
$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()));
}
'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,
}
/**
- * Закрытие текущей активной записи
- *
- * Устанавливает:
- * - 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;
}