refactor: убрать categoryRepo из ExportService, порядок из DefaultCategories

Категория лота приходит из прайслиста — запрашивать её из серверной БД
нарушало принцип local-first. Сигнатура NewExportService упрощена,
все call-sites обновлены.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 19:06:39 +03:00
parent ff262822e1
commit ddc00523e0
4 changed files with 23 additions and 34 deletions

View File

@@ -678,7 +678,7 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
syncService = sync.NewService(connMgr, local) syncService = sync.NewService(connMgr, local)
componentService := services.NewComponentService(nil, nil, nil) componentService := services.NewComponentService(nil, nil, nil)
quoteService := services.NewQuoteService(nil, nil, nil, local, nil) quoteService := services.NewQuoteService(nil, nil, nil, local, nil)
exportService := services.NewExportService(cfg.Export, nil, local) exportService := services.NewExportService(cfg.Export, local)
// isOnline function for local-first architecture // isOnline function for local-first architecture
isOnline := func() bool { isOnline := func() bool {

View File

@@ -30,7 +30,7 @@ func TestExportCSV_Success(t *testing.T) {
gin.SetMode(gin.TestMode) gin.SetMode(gin.TestMode)
// Create handler with mocks // Create handler with mocks
exportSvc := services.NewExportService(config.ExportConfig{}, nil, nil) exportSvc := services.NewExportService(config.ExportConfig{}, nil)
handler := NewExportHandler( handler := NewExportHandler(
exportSvc, exportSvc,
&mockConfigService{}, &mockConfigService{},
@@ -105,7 +105,7 @@ func TestExportCSV_Success(t *testing.T) {
func TestExportCSV_InvalidRequest(t *testing.T) { func TestExportCSV_InvalidRequest(t *testing.T) {
gin.SetMode(gin.TestMode) gin.SetMode(gin.TestMode)
exportSvc := services.NewExportService(config.ExportConfig{}, nil, nil) exportSvc := services.NewExportService(config.ExportConfig{}, nil)
handler := NewExportHandler( handler := NewExportHandler(
exportSvc, exportSvc,
&mockConfigService{}, &mockConfigService{},
@@ -139,7 +139,7 @@ func TestExportCSV_InvalidRequest(t *testing.T) {
func TestExportCSV_EmptyItems(t *testing.T) { func TestExportCSV_EmptyItems(t *testing.T) {
gin.SetMode(gin.TestMode) gin.SetMode(gin.TestMode)
exportSvc := services.NewExportService(config.ExportConfig{}, nil, nil) exportSvc := services.NewExportService(config.ExportConfig{}, nil)
handler := NewExportHandler( handler := NewExportHandler(
exportSvc, exportSvc,
&mockConfigService{}, &mockConfigService{},
@@ -181,7 +181,7 @@ func TestExportConfigCSV_Success(t *testing.T) {
CreatedAt: time.Now(), CreatedAt: time.Now(),
} }
exportSvc := services.NewExportService(config.ExportConfig{}, nil, nil) exportSvc := services.NewExportService(config.ExportConfig{}, nil)
handler := NewExportHandler( handler := NewExportHandler(
exportSvc, exportSvc,
&mockConfigService{config: mockConfig}, &mockConfigService{config: mockConfig},
@@ -228,7 +228,7 @@ func TestExportConfigCSV_Success(t *testing.T) {
func TestExportConfigCSV_NotFound(t *testing.T) { func TestExportConfigCSV_NotFound(t *testing.T) {
gin.SetMode(gin.TestMode) gin.SetMode(gin.TestMode)
exportSvc := services.NewExportService(config.ExportConfig{}, nil, nil) exportSvc := services.NewExportService(config.ExportConfig{}, nil)
handler := NewExportHandler( handler := NewExportHandler(
exportSvc, exportSvc,
&mockConfigService{err: errors.New("config not found")}, &mockConfigService{err: errors.New("config not found")},
@@ -271,7 +271,7 @@ func TestExportConfigCSV_EmptyItems(t *testing.T) {
CreatedAt: time.Now(), CreatedAt: time.Now(),
} }
exportSvc := services.NewExportService(config.ExportConfig{}, nil, nil) exportSvc := services.NewExportService(config.ExportConfig{}, nil)
handler := NewExportHandler( handler := NewExportHandler(
exportSvc, exportSvc,
&mockConfigService{config: mockConfig}, &mockConfigService{config: mockConfig},

View File

@@ -13,20 +13,17 @@ import (
"git.mchus.pro/mchus/quoteforge/internal/config" "git.mchus.pro/mchus/quoteforge/internal/config"
"git.mchus.pro/mchus/quoteforge/internal/localdb" "git.mchus.pro/mchus/quoteforge/internal/localdb"
"git.mchus.pro/mchus/quoteforge/internal/models" "git.mchus.pro/mchus/quoteforge/internal/models"
"git.mchus.pro/mchus/quoteforge/internal/repository"
) )
type ExportService struct { type ExportService struct {
config config.ExportConfig config config.ExportConfig
categoryRepo *repository.CategoryRepository localDB *localdb.LocalDB
localDB *localdb.LocalDB
} }
func NewExportService(cfg config.ExportConfig, categoryRepo *repository.CategoryRepository, local *localdb.LocalDB) *ExportService { func NewExportService(cfg config.ExportConfig, local *localdb.LocalDB) *ExportService {
return &ExportService{ return &ExportService{
config: cfg, config: cfg,
categoryRepo: categoryRepo, localDB: local,
localDB: local,
} }
} }
@@ -127,15 +124,7 @@ func (s *ExportService) ToCSV(w io.Writer, data *ProjectExportData) error {
return fmt.Errorf("failed to write header: %w", err) return fmt.Errorf("failed to write header: %w", err)
} }
// Build category order: start from DefaultCategories, override with live DB values if available.
categoryOrder := defaultCategoryOrder() categoryOrder := defaultCategoryOrder()
if s.categoryRepo != nil {
if categories, err := s.categoryRepo.GetAll(); err == nil {
for _, cat := range categories {
categoryOrder[cat.Code] = cat.DisplayOrder
}
}
}
for i, block := range data.Configs { for i, block := range data.Configs {
lineNo := block.Line lineNo := block.Line

View File

@@ -33,7 +33,7 @@ func newTestProjectData(items []ExportItem, article string, serverCount int) *Pr
} }
func TestToCSV_UTF8BOM(t *testing.T) { func TestToCSV_UTF8BOM(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := newTestProjectData([]ExportItem{ data := newTestProjectData([]ExportItem{
{ {
@@ -63,7 +63,7 @@ func TestToCSV_UTF8BOM(t *testing.T) {
} }
func TestToCSV_SemicolonDelimiter(t *testing.T) { func TestToCSV_SemicolonDelimiter(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := newTestProjectData([]ExportItem{ data := newTestProjectData([]ExportItem{
{ {
@@ -130,7 +130,7 @@ func TestToCSV_SemicolonDelimiter(t *testing.T) {
} }
func TestToCSV_ServerRow(t *testing.T) { func TestToCSV_ServerRow(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := newTestProjectData([]ExportItem{ data := newTestProjectData([]ExportItem{
{LotName: "LOT-001", Category: "CAT", Quantity: 1, UnitPrice: 100.0, TotalPrice: 100.0}, {LotName: "LOT-001", Category: "CAT", Quantity: 1, UnitPrice: 100.0, TotalPrice: 100.0},
@@ -175,7 +175,7 @@ func TestToCSV_ServerRow(t *testing.T) {
} }
func TestToCSV_CategorySorting(t *testing.T) { func TestToCSV_CategorySorting(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := newTestProjectData([]ExportItem{ data := newTestProjectData([]ExportItem{
{LotName: "LOT-001", Category: "CAT-A", Quantity: 1, UnitPrice: 100.0, TotalPrice: 100.0}, {LotName: "LOT-001", Category: "CAT-A", Quantity: 1, UnitPrice: 100.0, TotalPrice: 100.0},
@@ -214,7 +214,7 @@ func TestToCSV_CategorySorting(t *testing.T) {
} }
func TestToCSV_EmptyData(t *testing.T) { func TestToCSV_EmptyData(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := &ProjectExportData{ data := &ProjectExportData{
Configs: []ConfigExportBlock{}, Configs: []ConfigExportBlock{},
@@ -247,7 +247,7 @@ func TestToCSV_EmptyData(t *testing.T) {
} }
func TestToCSVBytes_BackwardCompat(t *testing.T) { func TestToCSVBytes_BackwardCompat(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := newTestProjectData([]ExportItem{ data := newTestProjectData([]ExportItem{
{LotName: "LOT-001", Category: "CAT", Quantity: 1, UnitPrice: 100.0, TotalPrice: 100.0}, {LotName: "LOT-001", Category: "CAT", Quantity: 1, UnitPrice: 100.0, TotalPrice: 100.0},
@@ -270,7 +270,7 @@ func TestToCSVBytes_BackwardCompat(t *testing.T) {
} }
func TestToCSV_WriterError(t *testing.T) { func TestToCSV_WriterError(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := newTestProjectData([]ExportItem{ data := newTestProjectData([]ExportItem{
{LotName: "LOT-001", Category: "CAT", Quantity: 1, UnitPrice: 100.0, TotalPrice: 100.0}, {LotName: "LOT-001", Category: "CAT", Quantity: 1, UnitPrice: 100.0, TotalPrice: 100.0},
@@ -284,7 +284,7 @@ func TestToCSV_WriterError(t *testing.T) {
} }
func TestToCSV_MultipleBlocks(t *testing.T) { func TestToCSV_MultipleBlocks(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := &ProjectExportData{ data := &ProjectExportData{
Configs: []ConfigExportBlock{ Configs: []ConfigExportBlock{
@@ -359,7 +359,7 @@ func TestToCSV_MultipleBlocks(t *testing.T) {
} }
func TestProjectToExportData_SortsByLine(t *testing.T) { func TestProjectToExportData_SortsByLine(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
configs := []models.Configuration{ configs := []models.Configuration{
{ {
@@ -445,7 +445,7 @@ func TestFormatPriceComma(t *testing.T) {
} }
func TestToPricingCSV_UsesSelectedColumns(t *testing.T) { func TestToPricingCSV_UsesSelectedColumns(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
data := &ProjectPricingExportData{ data := &ProjectPricingExportData{
Configs: []ProjectPricingExportConfig{ Configs: []ProjectPricingExportConfig{
{ {
@@ -519,7 +519,7 @@ func TestToPricingCSV_UsesSelectedColumns(t *testing.T) {
} }
func TestProjectToPricingExportData_UsesCartRowsWithoutBOM(t *testing.T) { func TestProjectToPricingExportData_UsesCartRowsWithoutBOM(t *testing.T) {
svc := NewExportService(config.ExportConfig{}, nil, nil) svc := NewExportService(config.ExportConfig{}, nil)
configs := []models.Configuration{ configs := []models.Configuration{
{ {
UUID: "cfg-1", UUID: "cfg-1",