refactor lot matching into shared module
This commit is contained in:
103
internal/warehouse/snapshot_test.go
Normal file
103
internal/warehouse/snapshot_test.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package warehouse
|
||||
|
||||
import (
|
||||
"math"
|
||||
"slices"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.mchus.pro/mchus/quoteforge/internal/models"
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestComputePricelistItemsFromStockLog(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
if err := db.AutoMigrate(&models.Lot{}, &models.LotPartnumber{}, &models.StockLog{}); err != nil {
|
||||
t.Fatalf("automigrate: %v", err)
|
||||
}
|
||||
|
||||
if err := db.Create(&models.Lot{LotName: "CPU_X"}).Error; err != nil {
|
||||
t.Fatalf("seed lot: %v", err)
|
||||
}
|
||||
if err := db.Create(&models.LotPartnumber{Partnumber: "PN-CPU-X", LotName: "CPU_X"}).Error; err != nil {
|
||||
t.Fatalf("seed mapping: %v", err)
|
||||
}
|
||||
|
||||
qtySmall := 1.0
|
||||
qtyBig := 9.0
|
||||
now := time.Now()
|
||||
rows := []models.StockLog{
|
||||
{Partnumber: "PN CPU X", Date: now, Price: 100, Qty: &qtySmall},
|
||||
{Partnumber: "CPU_X-EXTRA", Date: now, Price: 200, Qty: &qtyBig},
|
||||
}
|
||||
if err := db.Create(&rows).Error; err != nil {
|
||||
t.Fatalf("seed stock rows: %v", err)
|
||||
}
|
||||
|
||||
items, err := ComputePricelistItemsFromStockLog(db)
|
||||
if err != nil {
|
||||
t.Fatalf("ComputePricelistItemsFromStockLog: %v", err)
|
||||
}
|
||||
if len(items) != 1 {
|
||||
t.Fatalf("expected 1 item, got %d", len(items))
|
||||
}
|
||||
if items[0].LotName != "CPU_X" {
|
||||
t.Fatalf("expected lot CPU_X, got %s", items[0].LotName)
|
||||
}
|
||||
if math.Abs(items[0].Price-200) > 0.001 {
|
||||
t.Fatalf("expected weighted median 200, got %f", items[0].Price)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadLotMetricsLatestOnlyIncludesPartnumbers(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
if err := db.AutoMigrate(&models.Lot{}, &models.LotPartnumber{}, &models.StockLog{}); err != nil {
|
||||
t.Fatalf("automigrate: %v", err)
|
||||
}
|
||||
|
||||
if err := db.Create(&models.Lot{LotName: "CPU_X"}).Error; err != nil {
|
||||
t.Fatalf("seed lot: %v", err)
|
||||
}
|
||||
if err := db.Create(&models.LotPartnumber{Partnumber: "PN-MAPPED", LotName: "CPU_X"}).Error; err != nil {
|
||||
t.Fatalf("seed mapping: %v", err)
|
||||
}
|
||||
|
||||
oldDate := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
newDate := time.Date(2026, 1, 2, 0, 0, 0, 0, time.UTC)
|
||||
oldQty := 10.0
|
||||
newQty := 3.0
|
||||
rows := []models.StockLog{
|
||||
{Partnumber: "CPU_X-001", Date: oldDate, Price: 100, Qty: &oldQty},
|
||||
{Partnumber: "CPU_X-001", Date: newDate, Price: 100, Qty: &newQty},
|
||||
}
|
||||
if err := db.Create(&rows).Error; err != nil {
|
||||
t.Fatalf("seed stock rows: %v", err)
|
||||
}
|
||||
|
||||
qtyByLot, pnsByLot, err := LoadLotMetrics(db, []string{"CPU_X"}, true)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadLotMetrics: %v", err)
|
||||
}
|
||||
|
||||
if got := qtyByLot["CPU_X"]; math.Abs(got-3.0) > 0.001 {
|
||||
t.Fatalf("expected latest qty 3, got %f", got)
|
||||
}
|
||||
|
||||
pns := pnsByLot["CPU_X"]
|
||||
if !slices.Contains(pns, "PN-MAPPED") {
|
||||
t.Fatalf("expected mapped PN-MAPPED in partnumbers, got %v", pns)
|
||||
}
|
||||
if !slices.Contains(pns, "CPU_X-001") {
|
||||
t.Fatalf("expected stock CPU_X-001 in partnumbers, got %v", pns)
|
||||
}
|
||||
}
|
||||
|
||||
func openTestDB(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("open sqlite: %v", err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
Reference in New Issue
Block a user