From ba4a5324ed1cf40f95725e8b4f5d314e10131f42 Mon Sep 17 00:00:00 2001 From: Adnan Zahir Date: Mon, 6 Apr 2026 22:27:58 +0700 Subject: [PATCH] codex/fix: hidden product warehouse depletion and egg <= 0 --- .../repositories/warehouse.repository.go | 15 +++++ .../repositories/warehouse.repository_test.go | 63 +++++++++++++++++++ .../chickins/services/chickin.service.go | 26 +++++++- .../services/project_flock_kandang.service.go | 25 +++++++- .../services/projectflock.service.go | 35 +++++++++-- 5 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 internal/modules/master/warehouses/repositories/warehouse.repository_test.go diff --git a/internal/modules/master/warehouses/repositories/warehouse.repository.go b/internal/modules/master/warehouses/repositories/warehouse.repository.go index e879e01a..ff51a0b0 100644 --- a/internal/modules/master/warehouses/repositories/warehouse.repository.go +++ b/internal/modules/master/warehouses/repositories/warehouse.repository.go @@ -16,6 +16,7 @@ type WarehouseRepository interface { NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) IdExists(ctx context.Context, id uint) (bool, error) GetByKandangID(ctx context.Context, kandangId uint) (*entity.Warehouse, error) + GetByKandangIDAndLocationID(ctx context.Context, kandangId uint, locationId uint) (*entity.Warehouse, error) GetLatestByKandangID(ctx context.Context, kandangId uint) (*entity.Warehouse, error) } @@ -62,6 +63,20 @@ func (r *WarehouseRepositoryImpl) GetByKandangID(ctx context.Context, kandangId return &warehouse, nil } +func (r *WarehouseRepositoryImpl) GetByKandangIDAndLocationID(ctx context.Context, kandangId uint, locationId uint) (*entity.Warehouse, error) { + var warehouse entity.Warehouse + err := r.db.WithContext(ctx). + Where("kandang_id = ?", kandangId). + Where("location_id = ?", locationId). + Where("deleted_at IS NULL"). + Order("id ASC"). + First(&warehouse).Error + if err != nil { + return nil, err + } + return &warehouse, nil +} + func (r *WarehouseRepositoryImpl) GetLatestByKandangID(ctx context.Context, kandangId uint) (*entity.Warehouse, error) { var warehouse entity.Warehouse err := r.db.WithContext(ctx). diff --git a/internal/modules/master/warehouses/repositories/warehouse.repository_test.go b/internal/modules/master/warehouses/repositories/warehouse.repository_test.go new file mode 100644 index 00000000..f759cbc0 --- /dev/null +++ b/internal/modules/master/warehouses/repositories/warehouse.repository_test.go @@ -0,0 +1,63 @@ +package repository + +import ( + "context" + "testing" + + "github.com/glebarez/sqlite" + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" + "gorm.io/gorm" +) + +func TestGetByKandangIDAndLocationIDReturnsLocationMatchedWarehouse(t *testing.T) { + db := setupWarehouseRepositoryTestDB(t) + repo := NewWarehouseRepository(db) + + warehouse, err := repo.GetByKandangIDAndLocationID(context.Background(), 5, 13) + if err != nil { + t.Fatalf("expected location-matched warehouse, got error: %v", err) + } + if warehouse.Id != 33 { + t.Fatalf("expected warehouse 33, got %d", warehouse.Id) + } +} + +func TestGetByKandangIDKeepsLegacyFirstWarehouseBehavior(t *testing.T) { + db := setupWarehouseRepositoryTestDB(t) + repo := NewWarehouseRepository(db) + + warehouse, err := repo.GetByKandangID(context.Background(), 5) + if err != nil { + t.Fatalf("expected warehouse, got error: %v", err) + } + if warehouse.Id != 17 { + t.Fatalf("expected legacy first warehouse 17, got %d", warehouse.Id) + } +} + +func setupWarehouseRepositoryTestDB(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) + } + + if err := db.AutoMigrate(&entity.Warehouse{}); err != nil { + t.Fatalf("failed migrating warehouses: %v", err) + } + + warehouses := []entity.Warehouse{ + {Id: 17, Name: "Cijangkar 1", Type: "KANDANG", AreaId: 1, LocationId: uintPtr(1), KandangId: uintPtr(5), CreatedBy: 1}, + {Id: 33, Name: "Gudang Cijangkar 1", Type: "KANDANG", AreaId: 1, LocationId: uintPtr(13), KandangId: uintPtr(5), CreatedBy: 1}, + } + if err := db.Create(&warehouses).Error; err != nil { + t.Fatalf("failed seeding warehouses: %v", err) + } + + return db +} + +func uintPtr(v uint) *uint { + return &v +} diff --git a/internal/modules/production/chickins/services/chickin.service.go b/internal/modules/production/chickins/services/chickin.service.go index 3a342646..781a42f5 100644 --- a/internal/modules/production/chickins/services/chickin.service.go +++ b/internal/modules/production/chickins/services/chickin.service.go @@ -100,6 +100,25 @@ func (s chickinService) withRelations(db *gorm.DB) *gorm.DB { } +func resolveWarehouseForProjectFlockKandang(ctx context.Context, warehouseRepo rWarehouse.WarehouseRepository, kandangID uint, locationID uint) (*entity.Warehouse, error) { + if warehouseRepo == nil { + return nil, gorm.ErrRecordNotFound + } + if kandangID == 0 { + return nil, gorm.ErrRecordNotFound + } + if locationID != 0 { + warehouse, err := warehouseRepo.GetByKandangIDAndLocationID(ctx, kandangID, locationID) + if err == nil { + return warehouse, nil + } + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + } + return warehouseRepo.GetByKandangID(ctx, kandangID) +} + func (s chickinService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectChickin, int64, error) { if err := s.Validate.Struct(params); err != nil { return nil, 0, err @@ -182,7 +201,12 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti return nil, fiber.NewError(fiber.StatusNotFound, "Project Flock Kandang not found") } - warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), projectFlockKandang.KandangId) + warehouse, err := resolveWarehouseForProjectFlockKandang( + c.Context(), + s.WarehouseRepo, + projectFlockKandang.KandangId, + projectFlockKandang.ProjectFlock.LocationId, + ) if err != nil { return nil, fiber.NewError(fiber.StatusNotFound, "Warehouse for Kandang not found") } diff --git a/internal/modules/production/project-flock-kandangs/services/project_flock_kandang.service.go b/internal/modules/production/project-flock-kandangs/services/project_flock_kandang.service.go index 329fab80..1dc62062 100644 --- a/internal/modules/production/project-flock-kandangs/services/project_flock_kandang.service.go +++ b/internal/modules/production/project-flock-kandangs/services/project_flock_kandang.service.go @@ -87,6 +87,25 @@ func NewProjectFlockKandangService(repo repository.ProjectFlockKandangRepository } } +func resolveWarehouseForProjectFlockKandang(ctx context.Context, warehouseRepo rWarehouse.WarehouseRepository, pfk *entity.ProjectFlockKandang) (*entity.Warehouse, error) { + if warehouseRepo == nil || pfk == nil { + return nil, gorm.ErrRecordNotFound + } + if pfk.KandangId == 0 { + return nil, gorm.ErrRecordNotFound + } + if pfk.ProjectFlock.LocationId != 0 { + warehouse, err := warehouseRepo.GetByKandangIDAndLocationID(ctx, pfk.KandangId, pfk.ProjectFlock.LocationId) + if err == nil { + return warehouse, nil + } + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + } + return warehouseRepo.GetByKandangID(ctx, pfk.KandangId) +} + func (s projectFlockKandangService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandang, int64, error) { if err := s.Validate.Struct(params); err != nil { return nil, 0, err @@ -241,7 +260,7 @@ func (s projectFlockKandangService) getAvailableQuantities(c *fiber.Ctx, project return nil, nil } - warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), projectFlockKandang.Kandang.Id) + warehouse, err := resolveWarehouseForProjectFlockKandang(c.Context(), s.WarehouseRepo, projectFlockKandang) if err != nil || warehouse == nil { return nil, nil } @@ -300,7 +319,7 @@ func (s projectFlockKandangService) CheckClosing(c *fiber.Ctx, id uint) (*Closin stockRemain := make([]StockRemainingDetail, 0) if s.WarehouseRepo != nil && s.ProductWarehouseRepo != nil { - warehouse, werr := s.WarehouseRepo.GetByKandangID(c.Context(), pfk.KandangId) + warehouse, werr := resolveWarehouseForProjectFlockKandang(c.Context(), s.WarehouseRepo, pfk) if werr != nil { return nil, werr } @@ -464,7 +483,7 @@ func (s projectFlockKandangService) Closing(c *fiber.Ctx, id uint, req *validati } if s.WarehouseRepo != nil && s.ProductWarehouseRepo != nil { - warehouse, werr := s.WarehouseRepo.GetByKandangID(c.Context(), pfk.KandangId) + warehouse, werr := resolveWarehouseForProjectFlockKandang(c.Context(), s.WarehouseRepo, pfk) if werr != nil { return nil, werr } diff --git a/internal/modules/production/project_flocks/services/projectflock.service.go b/internal/modules/production/project_flocks/services/projectflock.service.go index f7812d0c..beaa0899 100644 --- a/internal/modules/production/project_flocks/services/projectflock.service.go +++ b/internal/modules/production/project_flocks/services/projectflock.service.go @@ -1075,6 +1075,25 @@ func (s projectflockService) kandangRepoWithTx(tx *gorm.DB) kandangRepository.Ka return kandangRepository.NewKandangRepository(s.Repository.DB()) } +func resolveWarehouseByKandangAndLocation(ctx context.Context, warehouseRepo warehouseRepository.WarehouseRepository, kandangID uint, locationID uint) (*entity.Warehouse, error) { + if warehouseRepo == nil { + return nil, gorm.ErrRecordNotFound + } + if kandangID == 0 { + return nil, gorm.ErrRecordNotFound + } + if locationID != 0 { + warehouse, err := warehouseRepo.GetByKandangIDAndLocationID(ctx, kandangID, locationID) + if err == nil { + return warehouse, nil + } + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + } + return warehouseRepo.GetByKandangID(ctx, kandangID) +} + func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx context.Context, dbTransaction *gorm.DB, records []*entity.ProjectFlockKandang) error { if len(records) == 0 { return nil @@ -1103,20 +1122,24 @@ func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx cont if dbTransaction != nil { db = dbTransaction } - var category string + type projectFlockMeta struct { + Category string `gorm:"column:category"` + LocationId uint `gorm:"column:location_id"` + } + var flockMeta projectFlockMeta if err := db.WithContext(ctx). Model(&entity.ProjectFlock{}). - Select("category"). + Select("category, location_id"). Where("id = ?", projectFlockID). - Scan(&category).Error; err != nil { + Scan(&flockMeta).Error; err != nil { return err } - if strings.TrimSpace(category) == "" { + if strings.TrimSpace(flockMeta.Category) == "" { return fiber.NewError(fiber.StatusBadRequest, "Project flock category tidak ditemukan") } prefixes := []string{"AYAM-"} - if strings.EqualFold(category, string(utils.ProjectFlockCategoryLaying)) { + if strings.EqualFold(flockMeta.Category, string(utils.ProjectFlockCategoryLaying)) { prefixes = append(prefixes, "TELUR") } @@ -1134,7 +1157,7 @@ func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx cont continue } - warehouse, err := warehouseRepo.GetByKandangID(ctx, record.KandangId) + warehouse, err := resolveWarehouseByKandangAndLocation(ctx, warehouseRepo, record.KandangId, flockMeta.LocationId) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Warehouse untuk kandang %d belum tersedia", record.KandangId))