refactor: убрать categoryRepo из ExportService, порядок из DefaultCategories
Категория лота приходит из прайслиста — запрашивать её из серверной БД нарушало принцип local-first. Сигнатура NewExportService упрощена, все call-sites обновлены. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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},
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user