$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');
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);
}
}
public function safeDown(): void
{
+ $this->dropForeignKey('fk_automark_product', 'products_1c_automark_predictions');
$this->dropTable('products_1c_automark_predictions');
}
}
namespace yii_app\records;
use yii\db\ActiveQuery;
+use yii_app\records\Products1c;
/**
* Предсказание авторазметки товара из 1С.
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']);
namespace yii_app\services;
+use Yii;
use yii_app\records\Products1c;
use yii_app\records\Products1cAutomarkPrediction;
use yii_app\records\Products1cNomenclature;
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;
+ }
}
/**
namespace yii_app\services\automark;
+use yii_app\records\Products1cAutomarkPrediction;
+
class RuleBasedParser
{
private const SPECIES_SREZY = [
size: $size,
color: $color,
confidence: $confidence,
- method: 'rule',
+ method: Products1cAutomarkPrediction::METHOD_RULE,
);
}
namespace yii_app\services\automark;
+use yii_app\records\Products1cAutomarkPrediction;
+
class SimilarityMatcher
{
private const STOP_WORDS = ['и', 'в', 'на', 'с', 'по', 'для', 'из', 'от', 'до', 'за', 'при', 'под'];
size: isset($bestItem['size']) ? (int) $bestItem['size'] : null,
color: $bestItem['color'] ?? null,
confidence: round($bestScore, 4),
- method: 'similarity',
+ method: Products1cAutomarkPrediction::METHOD_SIMILARITY,
);
}
'id',
[
'label' => 'Товар',
- 'value' => fn($m) => $m->product?->name ?? $m->product_id,
+ 'value' => fn($m) => Html::encode($m->product?->name ?? $m->product_id),
],
'category',
'species',