mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-06-09 15:07:49 +00:00
fix recording standar prod laying
This commit is contained in:
@@ -205,6 +205,7 @@ func AttachProductionStandards(ctx context.Context, db *gorm.DB, warnOnly bool,
|
||||
|
||||
standardDetailByStd := make(map[uint]map[int]*entity.ProductionStandardDetail, len(standardIDs))
|
||||
growthDetailByStd := make(map[uint]map[int]*entity.StandardGrowthDetail, len(standardIDs))
|
||||
firstCommonWeekByStd := make(map[uint]int, len(standardIDs))
|
||||
|
||||
for standardID := range standardIDs {
|
||||
details, err := standardDetailRepo.GetByProductionStandardID(ctx, standardID)
|
||||
@@ -242,6 +243,10 @@ func AttachProductionStandards(ctx context.Context, db *gorm.DB, warnOnly bool,
|
||||
growthMap[growth.Week] = &growth
|
||||
}
|
||||
growthDetailByStd[standardID] = growthMap
|
||||
|
||||
if firstCommonWeek, ok := firstCommonStandardWeek(detailMap, growthMap); ok {
|
||||
firstCommonWeekByStd[standardID] = firstCommonWeek
|
||||
}
|
||||
}
|
||||
|
||||
// Batch-load laying transfer targets → EARLIEST source PFK chick_in_date per target.
|
||||
@@ -284,6 +289,9 @@ func AttachProductionStandards(ctx context.Context, db *gorm.DB, warnOnly bool,
|
||||
continue
|
||||
}
|
||||
week := computeTransferAwareWeek(item, sourceChickInByTarget)
|
||||
if firstCommonWeek, ok := firstCommonWeekByStd[standardID]; ok {
|
||||
week = effectiveProductionStandardWeek(item, week, firstCommonWeek)
|
||||
}
|
||||
item.StandardWeek = &week
|
||||
cacheKey := standardKey{standardID: standardID, week: week}
|
||||
if cached, ok := cache[cacheKey]; ok {
|
||||
@@ -324,6 +332,38 @@ func applyProductionStandardValues(item *entity.Recording, values productionStan
|
||||
item.StandardFcr = fcr
|
||||
}
|
||||
|
||||
func firstCommonStandardWeek(
|
||||
detailMap map[int]*entity.ProductionStandardDetail,
|
||||
growthMap map[int]*entity.StandardGrowthDetail,
|
||||
) (int, bool) {
|
||||
firstWeek := 0
|
||||
for week := range detailMap {
|
||||
if week <= 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := growthMap[week]; !ok {
|
||||
continue
|
||||
}
|
||||
if firstWeek == 0 || week < firstWeek {
|
||||
firstWeek = week
|
||||
}
|
||||
}
|
||||
return firstWeek, firstWeek > 0
|
||||
}
|
||||
|
||||
func effectiveProductionStandardWeek(item *entity.Recording, actualWeek int, firstCommonWeek int) int {
|
||||
if item == nil || actualWeek <= 0 || firstCommonWeek <= 0 {
|
||||
return actualWeek
|
||||
}
|
||||
if !IsLayingRecording(*item) {
|
||||
return actualWeek
|
||||
}
|
||||
if actualWeek < firstCommonWeek {
|
||||
return firstCommonWeek
|
||||
}
|
||||
return actualWeek
|
||||
}
|
||||
|
||||
// collectLayingPFKIDs mengumpulkan semua project_flock_kandang_id dari recording laying
|
||||
func collectLayingPFKIDs(items []*entity.Recording) []uint {
|
||||
seen := make(map[uint]struct{})
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
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) {
|
||||
@@ -45,3 +50,126 @@ func TestMapEggsSetsProjectFlockKandangID(t *testing.T) {
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user