125 lines
3.6 KiB
Go
125 lines
3.6 KiB
Go
package services
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"git.mchus.pro/mchus/quoteforge/internal/models"
|
|
"git.mchus.pro/mchus/quoteforge/internal/repository"
|
|
"github.com/glebarez/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func TestCalculatePriceLevels_WithMissingLevel(t *testing.T) {
|
|
db := newPriceLevelsTestDB(t)
|
|
repo := repository.NewPricelistRepository(db)
|
|
service := NewQuoteService(nil, nil, repo, nil, nil)
|
|
|
|
estimate := seedPricelistWithItem(t, repo, "estimate", "CPU_X", 100)
|
|
_ = estimate
|
|
seedPricelistWithItem(t, repo, "warehouse", "CPU_X", 120)
|
|
|
|
result, err := service.CalculatePriceLevels(&PriceLevelsRequest{
|
|
Items: []struct {
|
|
LotName string `json:"lot_name"`
|
|
Quantity int `json:"quantity"`
|
|
}{
|
|
{LotName: "CPU_X", Quantity: 2},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("CalculatePriceLevels returned error: %v", err)
|
|
}
|
|
if len(result.Items) != 1 {
|
|
t.Fatalf("expected 1 item, got %d", len(result.Items))
|
|
}
|
|
item := result.Items[0]
|
|
if item.EstimatePrice == nil || *item.EstimatePrice != 100 {
|
|
t.Fatalf("expected estimate 100, got %#v", item.EstimatePrice)
|
|
}
|
|
if item.WarehousePrice == nil || *item.WarehousePrice != 120 {
|
|
t.Fatalf("expected warehouse 120, got %#v", item.WarehousePrice)
|
|
}
|
|
if item.CompetitorPrice != nil {
|
|
t.Fatalf("expected competitor nil, got %#v", item.CompetitorPrice)
|
|
}
|
|
if len(item.PriceMissing) != 1 || item.PriceMissing[0] != "competitor" {
|
|
t.Fatalf("expected price_missing [competitor], got %#v", item.PriceMissing)
|
|
}
|
|
if item.DeltaWhEstimateAbs == nil || *item.DeltaWhEstimateAbs != 20 {
|
|
t.Fatalf("expected delta abs 20, got %#v", item.DeltaWhEstimateAbs)
|
|
}
|
|
if item.DeltaWhEstimatePct == nil || *item.DeltaWhEstimatePct != 20 {
|
|
t.Fatalf("expected delta pct 20, got %#v", item.DeltaWhEstimatePct)
|
|
}
|
|
}
|
|
|
|
func TestCalculatePriceLevels_UsesExplicitPricelistIDs(t *testing.T) {
|
|
db := newPriceLevelsTestDB(t)
|
|
repo := repository.NewPricelistRepository(db)
|
|
service := NewQuoteService(nil, nil, repo, nil, nil)
|
|
|
|
olderEstimate := seedPricelistWithItem(t, repo, "estimate", "CPU_Y", 80)
|
|
seedPricelistWithItem(t, repo, "estimate", "CPU_Y", 90)
|
|
|
|
result, err := service.CalculatePriceLevels(&PriceLevelsRequest{
|
|
Items: []struct {
|
|
LotName string `json:"lot_name"`
|
|
Quantity int `json:"quantity"`
|
|
}{
|
|
{LotName: "CPU_Y", Quantity: 1},
|
|
},
|
|
PricelistIDs: map[string]uint{
|
|
"estimate": olderEstimate.ID,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("CalculatePriceLevels returned error: %v", err)
|
|
}
|
|
item := result.Items[0]
|
|
if item.EstimatePrice == nil || *item.EstimatePrice != 80 {
|
|
t.Fatalf("expected explicit estimate 80, got %#v", item.EstimatePrice)
|
|
}
|
|
}
|
|
|
|
func newPriceLevelsTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
|
|
if err != nil {
|
|
t.Fatalf("open sqlite: %v", err)
|
|
}
|
|
if err := db.AutoMigrate(&models.Pricelist{}, &models.PricelistItem{}); err != nil {
|
|
t.Fatalf("migrate: %v", err)
|
|
}
|
|
return db
|
|
}
|
|
|
|
func seedPricelistWithItem(t *testing.T, repo *repository.PricelistRepository, source, lot string, price float64) *models.Pricelist {
|
|
t.Helper()
|
|
version, err := repo.GenerateVersionBySource(source)
|
|
if err != nil {
|
|
t.Fatalf("GenerateVersionBySource: %v", err)
|
|
}
|
|
expiresAt := time.Now().Add(24 * time.Hour)
|
|
pl := &models.Pricelist{
|
|
Source: source,
|
|
Version: version,
|
|
CreatedBy: "test",
|
|
IsActive: true,
|
|
ExpiresAt: &expiresAt,
|
|
}
|
|
if err := repo.Create(pl); err != nil {
|
|
t.Fatalf("create pricelist: %v", err)
|
|
}
|
|
if err := repo.CreateItems([]models.PricelistItem{
|
|
{
|
|
PricelistID: pl.ID,
|
|
LotName: lot,
|
|
Price: price,
|
|
},
|
|
}); err != nil {
|
|
t.Fatalf("create items: %v", err)
|
|
}
|
|
return pl
|
|
}
|