package recording import ( "context" "testing" "time" "github.com/glebarez/sqlite" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/validations" "gitlab.com/mbugroup/lti-api.git/internal/utils" "gorm.io/gorm" ) func TestMapDepletionsKeepsSourceWarehouseRoutes(t *testing.T) { sourceA := uint(11) sourceB := uint(12) got := MapDepletions(99, []validation.Depletion{ {ProductWarehouseId: 21, SourceProductWarehouseId: &sourceA, Qty: 3}, {ProductWarehouseId: 21, SourceProductWarehouseId: &sourceA, Qty: 2}, {ProductWarehouseId: 21, SourceProductWarehouseId: &sourceB, Qty: 4}, }) if len(got) != 2 { t.Fatalf("expected 2 depletion routes, got %d", len(got)) } routeQty := DepletionTotalsByRoute(got, func(item entity.RecordingDepletion) (uint, *uint, float64) { return item.ProductWarehouseId, item.SourceProductWarehouseId, item.Qty }) if routeQty[DepletionRoute{ProductWarehouseId: 21, SourceProductWarehouseId: sourceA}] != 5 { t.Fatalf("expected source A qty 5, got %.2f", routeQty[DepletionRoute{ProductWarehouseId: 21, SourceProductWarehouseId: sourceA}]) } if routeQty[DepletionRoute{ProductWarehouseId: 21, SourceProductWarehouseId: sourceB}] != 4 { t.Fatalf("expected source B qty 4, got %.2f", routeQty[DepletionRoute{ProductWarehouseId: 21, SourceProductWarehouseId: sourceB}]) } } func TestMapEggsSetsProjectFlockKandangID(t *testing.T) { got := MapEggs(77, 44, 9, []validation.Egg{ {ProductWarehouseId: 88, Qty: 10}, }) if len(got) != 1 { t.Fatalf("expected 1 egg row, got %d", len(got)) } if got[0].ProjectFlockKandangId == nil || *got[0].ProjectFlockKandangId != 44 { t.Fatalf("expected project flock kandang id 44, got %+v", got[0].ProjectFlockKandangId) } } func TestAttachProductionStandardsClampsLayingPreStandardWeek(t *testing.T) { db := setupAttachProductionStandardTestDB(t) day := 91 recordDate := time.Date(2026, 4, 2, 0, 0, 0, 0, time.UTC) chickInDate := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC) recording := &entity.Recording{ Id: 501, ProjectFlockKandangId: 103, RecordDatetime: recordDate, Day: &day, ProjectFlockKandang: &entity.ProjectFlockKandang{ Id: 103, ProjectFlock: entity.ProjectFlock{ Id: 52, Category: string(utils.ProjectFlockCategoryLaying), ProductionStandardId: 1, ProductionStandard: entity.ProductionStandard{ Id: 1, Name: "STD Laying", }, }, }, } actualWeek := computeTransferAwareWeek(recording, map[uint]time.Time{103: chickInDate}) if actualWeek != 13 { t.Fatalf("expected actual transfer-aware week 13, got %d", actualWeek) } if err := AttachProductionStandards(context.Background(), db, false, nil, recording); err != nil { t.Fatalf("expected attach standard to succeed, got %v", err) } if recording.Day == nil || *recording.Day != 91 { t.Fatalf("expected actual recording day to remain 91, got %+v", recording.Day) } if recording.StandardWeek == nil || *recording.StandardWeek != 18 { t.Fatalf("expected effective standard week 18, got %+v", recording.StandardWeek) } if recording.StandardFeedIntake == nil || *recording.StandardFeedIntake != 120 { t.Fatalf("expected feed intake std from week 18, got %+v", recording.StandardFeedIntake) } if recording.StandardHenDay == nil || *recording.StandardHenDay != 80 { t.Fatalf("expected hen day std from week 18, got %+v", recording.StandardHenDay) } if recording.StandardFcr == nil || *recording.StandardFcr != 2.1 { t.Fatalf("expected fcr std from week 18, got %+v", recording.StandardFcr) } } func setupAttachProductionStandardTestDB(t *testing.T) *gorm.DB { t.Helper() db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=private"), &gorm.Config{}) if err != nil { t.Fatalf("failed opening sqlite db: %v", err) } statements := []string{ `CREATE TABLE production_standard_details ( id INTEGER PRIMARY KEY, production_standard_id INTEGER NOT NULL, week INTEGER NOT NULL, target_hen_day_production NUMERIC NULL, target_hen_house_production NUMERIC NULL, target_egg_weight NUMERIC NULL, target_egg_mass NUMERIC NULL, standard_fcr NUMERIC NULL, created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL )`, `CREATE TABLE standard_growth_details ( id INTEGER PRIMARY KEY, production_standard_id INTEGER NOT NULL, target_mean_bw NUMERIC NULL, max_depletion NUMERIC NULL, min_uniformity NUMERIC NOT NULL, week INTEGER NOT NULL, feed_intake NUMERIC NULL, created_at TIMESTAMP NULL, created_by INTEGER NOT NULL )`, `CREATE TABLE laying_transfer_targets ( id INTEGER PRIMARY KEY, laying_transfer_id INTEGER NOT NULL, target_project_flock_kandang_id INTEGER NOT NULL, deleted_at TIMESTAMP NULL )`, `CREATE TABLE laying_transfers ( id INTEGER PRIMARY KEY, source_project_flock_kandang_id INTEGER NULL, deleted_at TIMESTAMP NULL )`, `CREATE TABLE project_chickins ( id INTEGER PRIMARY KEY, project_flock_kandang_id INTEGER NOT NULL, chick_in_date TIMESTAMP NOT NULL, deleted_at TIMESTAMP NULL )`, `INSERT INTO production_standard_details (id, production_standard_id, week, target_hen_day_production, target_hen_house_production, target_egg_weight, target_egg_mass, standard_fcr) VALUES (1, 1, 18, 80, 70, 55, 44, 2.1)`, `INSERT INTO standard_growth_details (id, production_standard_id, week, feed_intake, max_depletion, min_uniformity, created_by) VALUES (1, 1, 18, 120, 1.5, 80, 1)`, `INSERT INTO laying_transfers (id, source_project_flock_kandang_id, deleted_at) VALUES (77, 83, NULL)`, `INSERT INTO laying_transfer_targets (id, laying_transfer_id, target_project_flock_kandang_id, deleted_at) VALUES (88, 77, 103, NULL)`, `INSERT INTO project_chickins (id, project_flock_kandang_id, chick_in_date, deleted_at) VALUES (99, 83, '2026-01-01 00:00:00', NULL)`, } for _, stmt := range statements { if err := db.Exec(stmt).Error; err != nil { t.Fatalf("failed preparing schema: %v", err) } } return db }