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:
@@ -35,6 +35,7 @@ type CreateItemInput struct {
|
||||
LotName string
|
||||
Price float64
|
||||
PriceMethod string
|
||||
Category string
|
||||
}
|
||||
|
||||
func NewService(db *gorm.DB, repo *repository.PricelistRepository, componentRepo *repository.ComponentRepository, pricingSvc *pricing.Service) *Service {
|
||||
@@ -170,28 +171,63 @@ func (s *Service) CreateForSourceWithProgress(createdBy, source string, sourceIt
|
||||
LotName: item.LotName,
|
||||
Price: item.Price,
|
||||
PriceMethod: item.PriceMethod,
|
||||
Category: item.Category,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(sourceItems) > 0 {
|
||||
// Load categories for all lot names if not provided
|
||||
lotNamesToLoad := make([]string, 0)
|
||||
for _, srcItem := range sourceItems {
|
||||
if strings.TrimSpace(srcItem.LotName) != "" && srcItem.Price > 0 && srcItem.Category == "" {
|
||||
lotNamesToLoad = append(lotNamesToLoad, strings.TrimSpace(srcItem.LotName))
|
||||
}
|
||||
}
|
||||
|
||||
categoryByLot := make(map[string]string)
|
||||
if len(lotNamesToLoad) > 0 {
|
||||
var lotCategories []struct {
|
||||
LotName string
|
||||
LotCategory string
|
||||
}
|
||||
if err := s.db.Table("lot").Select("lot_name, lot_category").Where("lot_name IN ?", lotNamesToLoad).Scan(&lotCategories).Error; err == nil {
|
||||
for _, lc := range lotCategories {
|
||||
categoryByLot[lc.LotName] = lc.LotCategory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items = make([]models.PricelistItem, 0, len(sourceItems))
|
||||
for _, srcItem := range sourceItems {
|
||||
if strings.TrimSpace(srcItem.LotName) == "" || srcItem.Price <= 0 {
|
||||
continue
|
||||
}
|
||||
category := srcItem.Category
|
||||
if category == "" {
|
||||
category = categoryByLot[strings.TrimSpace(srcItem.LotName)]
|
||||
}
|
||||
items = append(items, models.PricelistItem{
|
||||
PricelistID: pricelist.ID,
|
||||
LotName: strings.TrimSpace(srcItem.LotName),
|
||||
Price: srcItem.Price,
|
||||
PriceMethod: strings.TrimSpace(srcItem.PriceMethod),
|
||||
Category: category,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Default snapshot source for estimate and backward compatibility.
|
||||
var metadata []models.LotMetadata
|
||||
if err := s.db.Where("current_price IS NOT NULL AND current_price > 0").Find(&metadata).Error; err != nil {
|
||||
return nil, fmt.Errorf("getting lot metadata: %w", err)
|
||||
type LotMetadataWithCategory struct {
|
||||
models.LotMetadata
|
||||
LotCategory string
|
||||
}
|
||||
var metadata []LotMetadataWithCategory
|
||||
if err := s.db.Table("qt_lot_metadata as m").
|
||||
Select("m.*, COALESCE(l.lot_category, '') as lot_category").
|
||||
Joins("LEFT JOIN lot as l ON l.lot_name = m.lot_name").
|
||||
Where("m.current_price IS NOT NULL AND m.current_price > 0").
|
||||
Scan(&metadata).Error; err != nil {
|
||||
return nil, fmt.Errorf("getting lot metadata with categories: %w", err)
|
||||
}
|
||||
|
||||
// Create pricelist items with all price settings
|
||||
@@ -209,6 +245,7 @@ func (s *Service) CreateForSourceWithProgress(createdBy, source string, sourceIt
|
||||
PriceCoefficient: m.PriceCoefficient,
|
||||
ManualPrice: m.ManualPrice,
|
||||
MetaPrices: m.MetaPrices,
|
||||
Category: m.LotCategory,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user