Implement warehouse/lot pricing updates and configurator performance fixes
This commit is contained in:
@@ -47,6 +47,35 @@ func TestParseMXLRows(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMXLRows_EmptyQtyMarkedInvalid(t *testing.T) {
|
||||
content := strings.Join([]string{
|
||||
`MOXCEL`,
|
||||
`{16,2,{1,1,{"ru","Папка"}},0},1,`,
|
||||
`{16,2,{1,1,{"ru","Артикул"}},0},2,`,
|
||||
`{16,2,{1,1,{"ru","Описание"}},0},3,`,
|
||||
`{16,2,{1,1,{"ru","Вендор"}},0},4,`,
|
||||
`{16,2,{1,1,{"ru","Стоимость"}},0},5,`,
|
||||
`{16,2,{1,1,{"ru","Свободно"}},0},6,`,
|
||||
`{16,2,{1,1,{"ru","Серверы"}},0},1,`,
|
||||
`{16,2,{1,1,{"ru","CPU_X"}},0},2,`,
|
||||
`{16,2,{1,1,{"ru","Процессор"}},0},3,`,
|
||||
`{16,2,{1,1,{"ru","AMD"}},0},4,`,
|
||||
`{16,2,{1,1,{"ru","125,50"}},0},5,`,
|
||||
`{16,2,{1,1,{"ru",""}},0},6,`,
|
||||
}, "\n")
|
||||
|
||||
rows, err := parseMXLRows([]byte(content))
|
||||
if err != nil {
|
||||
t.Fatalf("parseMXLRows: %v", err)
|
||||
}
|
||||
if len(rows) != 1 {
|
||||
t.Fatalf("expected 1 row, got %d", len(rows))
|
||||
}
|
||||
if !rows[0].QtyInvalid {
|
||||
t.Fatalf("expected QtyInvalid=true for empty qty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseXLSXRows(t *testing.T) {
|
||||
xlsx := buildMinimalXLSX(t, []string{
|
||||
"Папка", "Артикул", "Описание", "Вендор", "Стоимость", "Свободно",
|
||||
@@ -114,9 +143,9 @@ func TestImportNoValidRowsKeepsStockLog(t *testing.T) {
|
||||
}
|
||||
|
||||
existing := models.StockLog{
|
||||
Lot: "CPU_A",
|
||||
Date: time.Now(),
|
||||
Price: 10,
|
||||
Partnumber: "CPU_A",
|
||||
Date: time.Now(),
|
||||
Price: 10,
|
||||
}
|
||||
if err := db.Create(&existing).Error; err != nil {
|
||||
t.Fatalf("seed stock_log: %v", err)
|
||||
@@ -152,14 +181,14 @@ func TestReplaceStockLogs(t *testing.T) {
|
||||
t.Fatalf("automigrate stock_log: %v", err)
|
||||
}
|
||||
|
||||
if err := db.Create(&models.StockLog{Lot: "OLD", Date: time.Now(), Price: 1}).Error; err != nil {
|
||||
if err := db.Create(&models.StockLog{Partnumber: "OLD", Date: time.Now(), Price: 1}).Error; err != nil {
|
||||
t.Fatalf("seed old row: %v", err)
|
||||
}
|
||||
|
||||
svc := NewStockImportService(db, nil)
|
||||
records := []models.StockLog{
|
||||
{Lot: "NEW_1", Date: time.Now(), Price: 2},
|
||||
{Lot: "NEW_2", Date: time.Now(), Price: 3},
|
||||
{Partnumber: "NEW_1", Date: time.Now(), Price: 2},
|
||||
{Partnumber: "NEW_2", Date: time.Now(), Price: 3},
|
||||
}
|
||||
|
||||
deleted, inserted, err := svc.replaceStockLogs(records)
|
||||
@@ -171,14 +200,73 @@ func TestReplaceStockLogs(t *testing.T) {
|
||||
}
|
||||
|
||||
var rows []models.StockLog
|
||||
if err := db.Order("lot").Find(&rows).Error; err != nil {
|
||||
if err := db.Order("partnumber").Find(&rows).Error; err != nil {
|
||||
t.Fatalf("read rows: %v", err)
|
||||
}
|
||||
if len(rows) != 2 || rows[0].Lot != "NEW_1" || rows[1].Lot != "NEW_2" {
|
||||
if len(rows) != 2 || rows[0].Partnumber != "NEW_1" || rows[1].Partnumber != "NEW_2" {
|
||||
t.Fatalf("unexpected rows after replace: %#v", rows)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWeightedMedian(t *testing.T) {
|
||||
got := weightedMedian([]weightedPricePoint{
|
||||
{price: 10, weight: 1},
|
||||
{price: 20, weight: 3},
|
||||
{price: 50, weight: 1},
|
||||
})
|
||||
if got != 20 {
|
||||
t.Fatalf("expected weighted median 20, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWeightedMedianFallbackToMedianWhenNoWeights(t *testing.T) {
|
||||
got := weightedMedian([]weightedPricePoint{
|
||||
{price: 10, weight: 0},
|
||||
{price: 20, weight: 0},
|
||||
{price: 30, weight: 0},
|
||||
})
|
||||
if got != 20 {
|
||||
t.Fatalf("expected fallback median 20, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildWarehousePricelistItems_UsesPrefixResolver(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
if err := db.AutoMigrate(&models.StockLog{}, &models.Lot{}, &models.LotPartnumber{}); err != nil {
|
||||
t.Fatalf("automigrate: %v", err)
|
||||
}
|
||||
|
||||
if err := db.Create(&models.Lot{LotName: "CPU_A"}).Error; err != nil {
|
||||
t.Fatalf("seed lot: %v", err)
|
||||
}
|
||||
|
||||
qty1 := 3.0
|
||||
qty2 := 1.0
|
||||
now := time.Now()
|
||||
rows := []models.StockLog{
|
||||
{Partnumber: "CPU_A-001", Date: now, Price: 100, Qty: &qty1},
|
||||
{Partnumber: "CPU_A-XYZ", Date: now, Price: 120, Qty: &qty2},
|
||||
}
|
||||
if err := db.Create(&rows).Error; err != nil {
|
||||
t.Fatalf("seed stock_log: %v", err)
|
||||
}
|
||||
|
||||
svc := NewStockImportService(db, nil)
|
||||
items, err := svc.buildWarehousePricelistItems()
|
||||
if err != nil {
|
||||
t.Fatalf("buildWarehousePricelistItems: %v", err)
|
||||
}
|
||||
if len(items) != 1 {
|
||||
t.Fatalf("expected 1 item, got %d", len(items))
|
||||
}
|
||||
if items[0].LotName != "CPU_A" {
|
||||
t.Fatalf("expected lot CPU_A, got %s", items[0].LotName)
|
||||
}
|
||||
if items[0].Price != 100 {
|
||||
t.Fatalf("expected weighted median 100, got %v", items[0].Price)
|
||||
}
|
||||
}
|
||||
|
||||
func openTestDB(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
|
||||
Reference in New Issue
Block a user