Add partnumber book snapshots for QuoteForge integration

- Migrations 026-028: qt_partnumber_books + qt_partnumber_book_items
  tables; is_primary_pn on lot_partnumbers; version VARCHAR(30);
  description VARCHAR(10000) on items (required by QuoteForge sync)
- Service: CreateSnapshot expands bundles, filters empty lot_name and
  ignored PNs, copies description, activates new book atomically,
  applies GFS retention (7d/5w/12m/10y) with explicit item deletion
- Task type TaskTypePartnumberBookCreate; handlers ListPartnumberBooks
  and CreatePartnumberBook; routes GET/POST /api/admin/pricing/partnumber-books
- UI: snapshot list + "Создать снапшот сопоставлений" button with
  progress polling on /vendor-mappings page
- Bible: history, api, background-tasks, vendor-mapping updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 22:16:16 +03:00
parent 225e1beda9
commit a4457a0a28
13 changed files with 751 additions and 32 deletions

View File

@@ -367,6 +367,7 @@ func setupRouter(cfg *config.Config, configPath string, connMgr *db.ConnectionMa
pricelistService := pricelist.NewService(mariaDB, pricelistRepo, componentRepo, pricingService)
stockImportService := services.NewStockImportService(mariaDB, pricelistService)
vendorMappingService := services.NewVendorMappingService(mariaDB)
partnumberBookService := services.NewPartnumberBookService(mariaDB)
// Create task manager
taskManager := tasks.NewManager()
@@ -383,6 +384,7 @@ func setupRouter(cfg *config.Config, configPath string, connMgr *db.ConnectionMa
statsRepo,
stockImportService,
vendorMappingService,
partnumberBookService,
dbUser,
taskManager,
)
@@ -642,6 +644,8 @@ func setupRouter(cfg *config.Config, configPath string, connMgr *db.ConnectionMa
pricingAdmin.POST("/alerts/:id/acknowledge", pricingHandler.AcknowledgeAlert)
pricingAdmin.POST("/alerts/:id/resolve", pricingHandler.ResolveAlert)
pricingAdmin.POST("/alerts/:id/ignore", pricingHandler.IgnoreAlert)
pricingAdmin.GET("/partnumber-books", pricingHandler.ListPartnumberBooks)
pricingAdmin.POST("/partnumber-books", pricingHandler.CreatePartnumberBook)
}
}