From 06591477b7e51e7085e7158e17af016c5678631a Mon Sep 17 00:00:00 2001 From: fomichev Date: Fri, 17 Apr 2026 17:28:33 +0300 Subject: [PATCH] =?utf8?q?fix(ERP-292):=20critical=20fixes=20=E2=80=94=20?= =?utf8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B8,=20?= =?utf8?q?=D1=82=D0=B8=D0=BF=D1=8B,=20FK=20drop,=20use=20imports,=20XSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- erp24/controllers/AutoMarkController.php | 20 ++++--- erp24/jobs/AutoMarkPredictionJob.php | 16 +----- ...reate_products_1c_automark_predictions.php | 1 + .../records/Products1cAutomarkPrediction.php | 6 +++ erp24/services/AutoMarkService.php | 52 ++++++++++++------- erp24/services/automark/RuleBasedParser.php | 4 +- erp24/services/automark/SimilarityMatcher.php | 4 +- erp24/views/auto-mark/index.php | 2 +- 8 files changed, 63 insertions(+), 42 deletions(-) diff --git a/erp24/controllers/AutoMarkController.php b/erp24/controllers/AutoMarkController.php index c5d62713..779a1be6 100644 --- a/erp24/controllers/AutoMarkController.php +++ b/erp24/controllers/AutoMarkController.php @@ -43,12 +43,20 @@ class AutoMarkController extends Controller $service = new AutoMarkService(); if ($action === 'approve') { - $prediction->status = Products1cAutomarkPrediction::STATUS_APPROVED; - $prediction->approved_by = Yii::$app->user->id; - $prediction->updated_at = date('Y-m-d H:i:s'); - $prediction->save(); - $service->applyApprovedPrediction($prediction->id); - Yii::$app->session->setFlash('success', 'Разметка применена.'); + $transaction = \Yii::$app->db->beginTransaction(); + try { + $prediction->status = Products1cAutomarkPrediction::STATUS_APPROVED; + $prediction->approved_by = Yii::$app->user->id; + $prediction->updated_at = date('Y-m-d H:i:s'); + if ($prediction->save()) { + $service->applyApprovedPrediction($prediction->id); + } + $transaction->commit(); + Yii::$app->session->setFlash('success', 'Разметка применена.'); + } catch (\Exception $e) { + $transaction->rollBack(); + Yii::$app->session->setFlash('error', 'Ошибка при применении разметки.'); + } } elseif ($action === 'reject') { $prediction->status = Products1cAutomarkPrediction::STATUS_REJECTED; $prediction->updated_at = date('Y-m-d H:i:s'); diff --git a/erp24/jobs/AutoMarkPredictionJob.php b/erp24/jobs/AutoMarkPredictionJob.php index ab21a1c9..4bbd1741 100644 --- a/erp24/jobs/AutoMarkPredictionJob.php +++ b/erp24/jobs/AutoMarkPredictionJob.php @@ -4,27 +4,15 @@ declare(strict_types=1); namespace yii_app\jobs; -use Yii; use yii\queue\JobInterface; use yii_app\services\AutoMarkService; class AutoMarkPredictionJob extends \yii\base\BaseObject implements JobInterface { - public $productId; + public string $productId; public function execute($queue): void { - $productId = $this->productId; - - try { - $service = new AutoMarkService(); - $service->predictForProduct($productId); - Yii::info("AutoMark прогноз успешно обработан для продукта ID {$productId}", 'automark'); - } catch (\Exception $e) { - Yii::error( - "Ошибка при обработке AutoMark прогноза для продукта ID {$productId}: " . $e->getMessage(), - 'automark' - ); - } + (new AutoMarkService())->predictForProduct($this->productId); } } diff --git a/erp24/migrations/m260417_000001_create_products_1c_automark_predictions.php b/erp24/migrations/m260417_000001_create_products_1c_automark_predictions.php index c261788a..376a83b3 100644 --- a/erp24/migrations/m260417_000001_create_products_1c_automark_predictions.php +++ b/erp24/migrations/m260417_000001_create_products_1c_automark_predictions.php @@ -38,6 +38,7 @@ class m260417_000001_create_products_1c_automark_predictions extends Migration public function safeDown(): void { + $this->dropForeignKey('fk_automark_product', 'products_1c_automark_predictions'); $this->dropTable('products_1c_automark_predictions'); } } diff --git a/erp24/records/Products1cAutomarkPrediction.php b/erp24/records/Products1cAutomarkPrediction.php index 201c3ac2..8ed27579 100644 --- a/erp24/records/Products1cAutomarkPrediction.php +++ b/erp24/records/Products1cAutomarkPrediction.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace yii_app\records; use yii\db\ActiveQuery; +use yii_app\records\Products1c; /** * Предсказание авторазметки товара из 1С. @@ -63,6 +64,11 @@ class Products1cAutomarkPrediction extends \yii\db\ActiveRecord return $this->status === self::STATUS_APPROVED; } + public function isRejected(): bool + { + return $this->status === self::STATUS_REJECTED; + } + public function getProduct(): ActiveQuery { return $this->hasOne(Products1c::class, ['id' => 'product_id']); diff --git a/erp24/services/AutoMarkService.php b/erp24/services/AutoMarkService.php index b524372b..fe5985dc 100644 --- a/erp24/services/AutoMarkService.php +++ b/erp24/services/AutoMarkService.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace yii_app\services; +use Yii; use yii_app\records\Products1c; use yii_app\records\Products1cAutomarkPrediction; use yii_app\records\Products1cNomenclature; @@ -62,28 +63,41 @@ class AutoMarkService return false; } - $nomenclature = Products1cNomenclature::findOne($prediction->product_id); - if ($nomenclature === null) { - $product = Products1c::findOne($prediction->product_id); - if ($product === null) { - return false; + $transaction = Yii::$app->db->beginTransaction(); + try { + $nomenclature = Products1cNomenclature::findOne($prediction->product_id); + if ($nomenclature === null) { + $product = Products1c::findOne($prediction->product_id); + if ($product === null) { + $transaction->rollBack(); + return false; + } + $nomenclature = new Products1cNomenclature(); + $nomenclature->id = $prediction->product_id; + $nomenclature->name = $product->name; + $nomenclature->location = ''; + $nomenclature->type_num = ''; } - $nomenclature = new Products1cNomenclature(); - $nomenclature->id = $prediction->product_id; - $nomenclature->name = $product->name; - $nomenclature->location = ''; - $nomenclature->type_num = ''; - } - $nomenclature->category = $prediction->category ?? $nomenclature->category; - $nomenclature->subcategory = $prediction->subcategory ?? $nomenclature->subcategory; - $nomenclature->species = $prediction->species ?? $nomenclature->species; - $nomenclature->sort = $prediction->sort ?? $nomenclature->sort; - $nomenclature->type = $prediction->type ?? $nomenclature->type; - $nomenclature->size = $prediction->size ?? $nomenclature->size; - $nomenclature->color = $prediction->color ?? $nomenclature->color; + $nomenclature->category = $prediction->category ?? $nomenclature->category; + $nomenclature->subcategory = $prediction->subcategory ?? $nomenclature->subcategory; + $nomenclature->species = $prediction->species ?? $nomenclature->species; + $nomenclature->sort = $prediction->sort ?? $nomenclature->sort; + $nomenclature->type = $prediction->type ?? $nomenclature->type; + $nomenclature->size = $prediction->size ?? $nomenclature->size; + $nomenclature->color = $prediction->color ?? $nomenclature->color; + + if (!$nomenclature->save()) { + $transaction->rollBack(); + return false; + } - return $nomenclature->save(); + $transaction->commit(); + return true; + } catch (\Exception $e) { + $transaction->rollBack(); + throw $e; + } } /** diff --git a/erp24/services/automark/RuleBasedParser.php b/erp24/services/automark/RuleBasedParser.php index 2b4d08f2..1b104d2d 100644 --- a/erp24/services/automark/RuleBasedParser.php +++ b/erp24/services/automark/RuleBasedParser.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace yii_app\services\automark; +use yii_app\records\Products1cAutomarkPrediction; + class RuleBasedParser { private const SPECIES_SREZY = [ @@ -66,7 +68,7 @@ class RuleBasedParser size: $size, color: $color, confidence: $confidence, - method: 'rule', + method: Products1cAutomarkPrediction::METHOD_RULE, ); } diff --git a/erp24/services/automark/SimilarityMatcher.php b/erp24/services/automark/SimilarityMatcher.php index 4de5e2c5..45623d12 100644 --- a/erp24/services/automark/SimilarityMatcher.php +++ b/erp24/services/automark/SimilarityMatcher.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace yii_app\services\automark; +use yii_app\records\Products1cAutomarkPrediction; + class SimilarityMatcher { private const STOP_WORDS = ['и', 'в', 'на', 'с', 'по', 'для', 'из', 'от', 'до', 'за', 'при', 'под']; @@ -50,7 +52,7 @@ class SimilarityMatcher size: isset($bestItem['size']) ? (int) $bestItem['size'] : null, color: $bestItem['color'] ?? null, confidence: round($bestScore, 4), - method: 'similarity', + method: Products1cAutomarkPrediction::METHOD_SIMILARITY, ); } diff --git a/erp24/views/auto-mark/index.php b/erp24/views/auto-mark/index.php index 1bf8a9d0..4366b872 100644 --- a/erp24/views/auto-mark/index.php +++ b/erp24/views/auto-mark/index.php @@ -21,7 +21,7 @@ $this->title = 'Авторазметка товаров'; 'id', [ 'label' => 'Товар', - 'value' => fn($m) => $m->product?->name ?? $m->product_id, + 'value' => fn($m) => Html::encode($m->product?->name ?? $m->product_id), ], 'category', 'species', -- 2.39.5