fix: потоковая отправка прогресса создания прайслиста и исправление маппинга колонки категории

Две ключевые исправления:

1. Потоковая отправка прогресса создания (SSE):
   - Эндпоинт CreateWithProgress теперь отправляет Server-Sent Events
     вместо возврата JSON с task_id
   - Полирует статус задачи и отправляет обновления прогресса в реальном времени
   - Отправляет финальное событие с данными прайслиста или ошибкой
   - Фронтенд уже ожидал этого формата SSE

2. Исправление маппинга колонки lot_category:
   - Добавлен явный тег column в поле Category модели PricelistItem
     чтобы маппиться на колонку 'lot_category' в БД
   - Категория теперь хранится как снимок в таблице pricelist_items
   - Обновлены запросы репозитория для использования сохраненной
     категории вместо динамических JOIN с таблицей lot

Это исправляет ошибки:
- "Создание прервано: не получен результат" (фронтенд ожидал streaming)
- "Unknown column 'category' in 'INSERT INTO'" (несоответствие схемы БД)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-02-10 15:17:16 +03:00
parent 7d671203d7
commit c47c93ab31
6 changed files with 148 additions and 11 deletions

View File

@@ -13,6 +13,7 @@ type SnapshotItem struct {
LotName string
Price float64
PriceMethod string
Category string // Historical snapshot of lot_category
}
type weightedPricePoint struct {
@@ -61,8 +62,31 @@ func ComputePricelistItemsFromStockLog(db *gorm.DB) ([]SnapshotItem, error) {
if price <= 0 {
continue
}
items = append(items, SnapshotItem{LotName: lot, Price: price, PriceMethod: "weighted_median"})
items = append(items, SnapshotItem{LotName: lot, Price: price, PriceMethod: "weighted_median", Category: ""})
}
// Load categories for all lots in a single query
if len(items) > 0 {
lotNames := make([]string, 0, len(items))
lotToIdx := make(map[string]int, len(items))
for i, item := range items {
lotToIdx[item.LotName] = i
lotNames = append(lotNames, item.LotName)
}
var categories []struct {
LotName string
LotCategory string
}
if err := db.Table("lot").Select("lot_name, lot_category").Where("lot_name IN ?", lotNames).Scan(&categories).Error; err == nil {
for _, cat := range categories {
if idx, ok := lotToIdx[cat.LotName]; ok {
items[idx].Category = cat.LotCategory
}
}
}
}
sort.Slice(items, func(i, j int) bool { return items[i].LotName < items[j].LotName })
return items, nil
}