- New unified append-only quote log table parts_log replaces three separate log tables (stock_log, partnumber_log_competitors, lot_log) - Migrations 042-049: extend supplier, create parts_log/import_formats/ ignore_rules, rework qt_lot_metadata composite PK, add lead_time_weeks to pricelist_items, backfill data, migrate ignore rules - New services: PartsLogBackfillService, ImportFormatService, UnifiedImportService; new world pricelist type (all supplier types) - qt_lot_metadata PK changed to (lot_name, pricelist_type); all queries now filter WHERE pricelist_type='estimate' - Fix pre-existing bug: qt_component_usage_stats column names quotes_last30d/quotes_last7d (no underscore) — added explicit gorm tags - Bible: full table inventory, baseline schema snapshot, updated pricelist/ data-rules/api/history/architecture docs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
68 lines
2.0 KiB
Go
68 lines
2.0 KiB
Go
package services
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"git.mchus.pro/mchus/priceforge/internal/models"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// ImportFormatService manages qt_import_formats records.
|
|
type ImportFormatService struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewImportFormatService(db *gorm.DB) *ImportFormatService {
|
|
return &ImportFormatService{db: db}
|
|
}
|
|
|
|
// List returns all active import formats.
|
|
func (s *ImportFormatService) List() ([]models.ImportFormat, error) {
|
|
var formats []models.ImportFormat
|
|
if err := s.db.Where("is_active = ?", true).Order("name").Find(&formats).Error; err != nil {
|
|
return nil, fmt.Errorf("list import formats: %w", err)
|
|
}
|
|
return formats, nil
|
|
}
|
|
|
|
// GetByCode returns an import format by format_code.
|
|
func (s *ImportFormatService) GetByCode(code string) (*models.ImportFormat, error) {
|
|
var f models.ImportFormat
|
|
if err := s.db.Where("format_code = ?", code).First(&f).Error; err != nil {
|
|
return nil, fmt.Errorf("get import format %q: %w", code, err)
|
|
}
|
|
return &f, nil
|
|
}
|
|
|
|
// Save creates or updates an import format.
|
|
func (s *ImportFormatService) Save(f *models.ImportFormat) error {
|
|
if f.FormatCode == "" {
|
|
return fmt.Errorf("format_code is required")
|
|
}
|
|
if err := s.db.Save(f).Error; err != nil {
|
|
return fmt.Errorf("save import format: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Delete marks an import format as inactive.
|
|
func (s *ImportFormatService) Delete(code string) error {
|
|
return s.db.Model(&models.ImportFormat{}).
|
|
Where("format_code = ?", code).
|
|
Update("is_active", false).Error
|
|
}
|
|
|
|
// ParseColumnMapping decodes the column_mapping JSON from a format into
|
|
// a CompetitorColumnMapping struct (shared format for all sources).
|
|
func (s *ImportFormatService) ParseColumnMapping(f *models.ImportFormat) (*models.CompetitorColumnMapping, error) {
|
|
if len(f.ColumnMapping) == 0 {
|
|
return &models.CompetitorColumnMapping{}, nil
|
|
}
|
|
var m models.CompetitorColumnMapping
|
|
if err := json.Unmarshal(f.ColumnMapping, &m); err != nil {
|
|
return nil, fmt.Errorf("parse column_mapping for format %q: %w", f.FormatCode, err)
|
|
}
|
|
return &m, nil
|
|
}
|