236 lines
6.3 KiB
Go
236 lines
6.3 KiB
Go
package repository
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.mchus.pro/mchus/quoteforge/internal/models"
|
|
"github.com/glebarez/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func TestGenerateVersion_FirstOfDay(t *testing.T) {
|
|
repo := newTestPricelistRepository(t)
|
|
|
|
version, err := repo.GenerateVersionBySource(string(models.PricelistSourceEstimate))
|
|
if err != nil {
|
|
t.Fatalf("GenerateVersionBySource returned error: %v", err)
|
|
}
|
|
|
|
today := time.Now().Format("2006-01-02")
|
|
want := fmt.Sprintf("E-%s-001", today)
|
|
if version != want {
|
|
t.Fatalf("expected %s, got %s", want, version)
|
|
}
|
|
}
|
|
|
|
func TestGenerateVersion_UsesMaxSuffixNotCount(t *testing.T) {
|
|
repo := newTestPricelistRepository(t)
|
|
today := time.Now().Format("2006-01-02")
|
|
|
|
seed := []models.Pricelist{
|
|
{Source: string(models.PricelistSourceEstimate), Version: fmt.Sprintf("E-%s-001", today), CreatedBy: "test", IsActive: true},
|
|
{Source: string(models.PricelistSourceEstimate), Version: fmt.Sprintf("E-%s-003", today), CreatedBy: "test", IsActive: true},
|
|
}
|
|
for _, pl := range seed {
|
|
if err := repo.Create(&pl); err != nil {
|
|
t.Fatalf("seed insert failed: %v", err)
|
|
}
|
|
}
|
|
|
|
version, err := repo.GenerateVersionBySource(string(models.PricelistSourceEstimate))
|
|
if err != nil {
|
|
t.Fatalf("GenerateVersionBySource returned error: %v", err)
|
|
}
|
|
|
|
want := fmt.Sprintf("E-%s-004", today)
|
|
if version != want {
|
|
t.Fatalf("expected %s, got %s", want, version)
|
|
}
|
|
}
|
|
|
|
func TestGenerateVersion_IsolatedBySource(t *testing.T) {
|
|
repo := newTestPricelistRepository(t)
|
|
today := time.Now().Format("2006-01-02")
|
|
|
|
seed := []models.Pricelist{
|
|
{Source: string(models.PricelistSourceEstimate), Version: fmt.Sprintf("E-%s-009", today), CreatedBy: "test", IsActive: true},
|
|
{Source: string(models.PricelistSourceWarehouse), Version: fmt.Sprintf("S-%s-002", today), CreatedBy: "test", IsActive: true},
|
|
}
|
|
for _, pl := range seed {
|
|
if err := repo.Create(&pl); err != nil {
|
|
t.Fatalf("seed insert failed: %v", err)
|
|
}
|
|
}
|
|
|
|
version, err := repo.GenerateVersionBySource(string(models.PricelistSourceWarehouse))
|
|
if err != nil {
|
|
t.Fatalf("GenerateVersionBySource returned error: %v", err)
|
|
}
|
|
|
|
want := fmt.Sprintf("S-%s-003", today)
|
|
if version != want {
|
|
t.Fatalf("expected %s, got %s", want, version)
|
|
}
|
|
}
|
|
|
|
func TestGetItems_WarehouseAvailableQtyUsesPrefixResolver(t *testing.T) {
|
|
repo := newTestPricelistRepository(t)
|
|
db := repo.db
|
|
|
|
warehouse := models.Pricelist{
|
|
Source: string(models.PricelistSourceWarehouse),
|
|
Version: "S-2026-02-07-001",
|
|
CreatedBy: "test",
|
|
IsActive: true,
|
|
}
|
|
if err := db.Create(&warehouse).Error; err != nil {
|
|
t.Fatalf("create pricelist: %v", err)
|
|
}
|
|
if err := db.Create(&models.PricelistItem{
|
|
PricelistID: warehouse.ID,
|
|
LotName: "SSD_NVME_03.2T",
|
|
Price: 100,
|
|
}).Error; err != nil {
|
|
t.Fatalf("create pricelist item: %v", err)
|
|
}
|
|
if err := db.Create(&models.Lot{LotName: "SSD_NVME_03.2T"}).Error; err != nil {
|
|
t.Fatalf("create lot: %v", err)
|
|
}
|
|
qty := 5.0
|
|
if err := db.Create(&models.StockLog{
|
|
Partnumber: "SSD_NVME_03.2T_GEN3_P4610",
|
|
Date: time.Now(),
|
|
Price: 200,
|
|
Qty: &qty,
|
|
}).Error; err != nil {
|
|
t.Fatalf("create stock log: %v", err)
|
|
}
|
|
|
|
items, total, err := repo.GetItems(warehouse.ID, 0, 20, "")
|
|
if err != nil {
|
|
t.Fatalf("GetItems: %v", err)
|
|
}
|
|
if total != 1 {
|
|
t.Fatalf("expected total=1, got %d", total)
|
|
}
|
|
if len(items) != 1 {
|
|
t.Fatalf("expected 1 item, got %d", len(items))
|
|
}
|
|
if items[0].AvailableQty == nil {
|
|
t.Fatalf("expected available qty to be set")
|
|
}
|
|
if *items[0].AvailableQty != 5 {
|
|
t.Fatalf("expected available qty=5, got %v", *items[0].AvailableQty)
|
|
}
|
|
}
|
|
|
|
func TestGetLatestActiveBySource_SkipsPricelistsWithoutItems(t *testing.T) {
|
|
repo := newTestPricelistRepository(t)
|
|
db := repo.db
|
|
ts := time.Now().Add(-time.Minute)
|
|
source := "test-estimate-skip-empty"
|
|
|
|
emptyLatest := models.Pricelist{
|
|
Source: source,
|
|
Version: "E-empty",
|
|
CreatedBy: "test",
|
|
IsActive: true,
|
|
CreatedAt: ts.Add(2 * time.Second),
|
|
}
|
|
if err := db.Create(&emptyLatest).Error; err != nil {
|
|
t.Fatalf("create empty pricelist: %v", err)
|
|
}
|
|
|
|
withItems := models.Pricelist{
|
|
Source: source,
|
|
Version: "E-with-items",
|
|
CreatedBy: "test",
|
|
IsActive: true,
|
|
CreatedAt: ts,
|
|
}
|
|
if err := db.Create(&withItems).Error; err != nil {
|
|
t.Fatalf("create pricelist with items: %v", err)
|
|
}
|
|
if err := db.Create(&models.PricelistItem{
|
|
PricelistID: withItems.ID,
|
|
LotName: "CPU_A",
|
|
Price: 100,
|
|
}).Error; err != nil {
|
|
t.Fatalf("create pricelist item: %v", err)
|
|
}
|
|
|
|
got, err := repo.GetLatestActiveBySource(source)
|
|
if err != nil {
|
|
t.Fatalf("GetLatestActiveBySource: %v", err)
|
|
}
|
|
if got.ID != withItems.ID {
|
|
t.Fatalf("expected pricelist with items id=%d, got id=%d", withItems.ID, got.ID)
|
|
}
|
|
}
|
|
|
|
func TestGetLatestActiveBySource_TieBreaksByID(t *testing.T) {
|
|
repo := newTestPricelistRepository(t)
|
|
db := repo.db
|
|
ts := time.Now().Add(-time.Minute)
|
|
source := "test-warehouse-tie-break"
|
|
|
|
first := models.Pricelist{
|
|
Source: source,
|
|
Version: "S-1",
|
|
CreatedBy: "test",
|
|
IsActive: true,
|
|
CreatedAt: ts,
|
|
}
|
|
if err := db.Create(&first).Error; err != nil {
|
|
t.Fatalf("create first pricelist: %v", err)
|
|
}
|
|
if err := db.Create(&models.PricelistItem{
|
|
PricelistID: first.ID,
|
|
LotName: "CPU_A",
|
|
Price: 101,
|
|
}).Error; err != nil {
|
|
t.Fatalf("create first item: %v", err)
|
|
}
|
|
|
|
second := models.Pricelist{
|
|
Source: source,
|
|
Version: "S-2",
|
|
CreatedBy: "test",
|
|
IsActive: true,
|
|
CreatedAt: ts,
|
|
}
|
|
if err := db.Create(&second).Error; err != nil {
|
|
t.Fatalf("create second pricelist: %v", err)
|
|
}
|
|
if err := db.Create(&models.PricelistItem{
|
|
PricelistID: second.ID,
|
|
LotName: "CPU_A",
|
|
Price: 102,
|
|
}).Error; err != nil {
|
|
t.Fatalf("create second item: %v", err)
|
|
}
|
|
|
|
got, err := repo.GetLatestActiveBySource(source)
|
|
if err != nil {
|
|
t.Fatalf("GetLatestActiveBySource: %v", err)
|
|
}
|
|
if got.ID != second.ID {
|
|
t.Fatalf("expected later inserted pricelist id=%d, got id=%d", second.ID, got.ID)
|
|
}
|
|
}
|
|
|
|
func newTestPricelistRepository(t *testing.T) *PricelistRepository {
|
|
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{}, &models.Lot{}, &models.LotPartnumber{}, &models.StockLog{}); err != nil {
|
|
t.Fatalf("migrate: %v", err)
|
|
}
|
|
return NewPricelistRepository(db)
|
|
}
|