feat(BE-281): unfinished uniformity and create project flock triger productwarehouse and add new filtering lookup

This commit is contained in:
ragilap
2025-12-29 00:21:26 +07:00
parent cdfa77566c
commit 644896edfa
25 changed files with 2043 additions and 8 deletions
@@ -21,6 +21,7 @@ import (
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
@@ -37,6 +38,7 @@ type ProjectflockService interface {
GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID uint) (float64, error)
DeleteOne(ctx *fiber.Ctx, id uint) error
GetProjectFlockKandangByProjectAndKandang(ctx *fiber.Ctx, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, float64, error)
GetProjectFlockKandangPopulation(ctx *fiber.Ctx, projectFlockKandangID uint) (float64, error)
GetPeriodSummary(ctx *fiber.Ctx, locationID uint) ([]KandangPeriodSummary, error)
GetProjectPeriods(ctx *fiber.Ctx, projectIDs []uint) (map[uint]int, error)
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlock, error)
@@ -54,6 +56,8 @@ type projectflockService struct {
ProductWarehouseRepo productWarehouseRepository.ProductWarehouseRepository
ProjectBudgetRepo projectBudgetRepository.ProjectBudgetRepository
PivotRepo repository.ProjectFlockKandangRepository
PopulationRepo repository.ProjectFlockPopulationRepository
RecordingRepo recordingRepo.RecordingRepository
ApprovalSvc commonSvc.ApprovalService
approvalWorkflow approvalutils.ApprovalWorkflowKey
}
@@ -73,6 +77,8 @@ func NewProjectflockService(
productWarehouseRepo productWarehouseRepository.ProductWarehouseRepository,
projectBudgetRepo projectBudgetRepository.ProjectBudgetRepository,
nonstockRepo nonstockRepository.NonstockRepository,
populationRepo repository.ProjectFlockPopulationRepository,
recordingRepo recordingRepo.RecordingRepository,
approvalSvc commonSvc.ApprovalService,
validate *validator.Validate,
@@ -86,7 +92,10 @@ func NewProjectflockService(
NonstockRepo: nonstockRepo,
WarehouseRepo: warehouseRepo,
ProductWarehouseRepo: productWarehouseRepo,
ProjectBudgetRepo: projectBudgetRepo,
PivotRepo: pivotRepo,
PopulationRepo: populationRepo,
RecordingRepo: recordingRepo,
ApprovalSvc: approvalSvc,
approvalWorkflow: utils.ApprovalWorkflowProjectFlock,
}
@@ -417,6 +426,34 @@ func (s projectflockService) GetProjectFlockKandangByProjectAndKandang(ctx *fibe
return pfk, availableQuantity, nil
}
func (s projectflockService) GetProjectFlockKandangPopulation(ctx *fiber.Ctx, projectFlockKandangID uint) (float64, error) {
if s.PopulationRepo == nil {
return 0, fiber.NewError(fiber.StatusInternalServerError, "Project flock population repository is not configured")
}
if projectFlockKandangID == 0 {
return 0, fiber.NewError(fiber.StatusBadRequest, "project_flock_kandang_id is required")
}
if s.RecordingRepo != nil {
latest, err := s.RecordingRepo.GetLatestByProjectFlockKandangID(ctx.Context(), projectFlockKandangID)
if err != nil {
s.Log.Errorf("Failed to fetch latest recording for project flock kandang %d: %+v", projectFlockKandangID, err)
return 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock kandang population")
}
if latest != nil && latest.TotalChickQty != nil && *latest.TotalChickQty > 0 {
return *latest.TotalChickQty, nil
}
}
total, err := s.PopulationRepo.GetAvailableQtyByProjectFlockKandangID(ctx.Context(), projectFlockKandangID)
if err != nil {
s.Log.Errorf("Failed to fetch project flock kandang population %d: %+v", projectFlockKandangID, err)
return 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock kandang population")
}
return total, nil
}
func (s projectflockService) GetProjectFlockKandangByParams(ctx *fiber.Ctx, idStr string, projectFlockIdStr string, kandangIdStr string) (*entity.ProjectFlockKandang, float64, error) {
idStr = strings.TrimSpace(idStr)
projectFlockIdStr = strings.TrimSpace(projectFlockIdStr)
@@ -793,6 +830,9 @@ func (s projectflockService) attachKandangs(ctx context.Context, dbTransaction *
}
return fiber.NewError(fiber.StatusInternalServerError, "Failed to persist project flock history")
}
if err := s.ensureProjectFlockKandangProductWarehouses(ctx, dbTransaction, records); err != nil {
return err
}
return nil
}
@@ -818,6 +858,23 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction *
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Tidak dapat melepas kandang karena sudah memiliki recording: %s", strings.Join(names, ", ")))
}
pfkIDs, err := s.pivotRepoWithTx(dbTransaction).ListIDsByProjectAndKandang(ctx, projectFlockID, kandangIDs)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to load project flock kandang ids")
}
if len(pfkIDs) > 0 {
pwRepo := s.ProductWarehouseRepo
if dbTransaction != nil {
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
} else if pwRepo == nil {
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(s.Repository.DB())
}
if err := pwRepo.DeleteByProjectFlockKandangIDs(ctx, pfkIDs); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove product warehouses for project flock kandang")
}
}
if resetStatus {
if err := s.kandangRepoWithTx(dbTransaction).UpdateStatusByIDs(ctx, kandangIDs, utils.KandangStatusNonActive); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update kandangs status")
@@ -854,6 +911,78 @@ func (s projectflockService) kandangRepoWithTx(tx *gorm.DB) kandangRepository.Ka
return kandangRepository.NewKandangRepository(s.Repository.DB())
}
func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx context.Context, dbTransaction *gorm.DB, records []*entity.ProjectFlockKandang) error {
if len(records) == 0 {
return nil
}
pwRepo := s.ProductWarehouseRepo
if dbTransaction != nil {
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
} else if pwRepo == nil {
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(s.Repository.DB())
}
warehouseRepo := s.WarehouseRepo
if dbTransaction != nil {
warehouseRepo = warehouseRepository.NewWarehouseRepository(dbTransaction)
} else if warehouseRepo == nil {
warehouseRepo = warehouseRepository.NewWarehouseRepository(s.Repository.DB())
}
flags := []utils.FlagType{
utils.FlagAyamAfkir,
utils.FlagAyamCulling,
utils.FlagAyamMati,
utils.FlagTelurPecah,
utils.FlagTelurUtuh,
}
productIDs := make(map[utils.FlagType]uint, len(flags))
for _, flag := range flags {
product, err := pwRepo.GetFirstProductByFlag(ctx, string(flag))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Product untuk flag %s tidak ditemukan", flag))
}
return err
}
productIDs[flag] = product.Id
}
for _, record := range records {
if record == nil || record.Id == 0 {
continue
}
warehouse, err := warehouseRepo.GetByKandangID(ctx, record.KandangId)
if err != nil {
return err
}
for _, flag := range flags {
productID := productIDs[flag]
if _, err := pwRepo.GetByProductWarehouseAndProjectFlockKandang(ctx, productID, warehouse.Id, record.Id); err == nil {
continue
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
newPW := entity.ProductWarehouse{
ProductId: productID,
WarehouseId: warehouse.Id,
ProjectFlockKandangId: &record.Id,
Quantity: 0,
}
if err := pwRepo.CreateOne(ctx, &newPW, nil); err != nil {
return err
}
}
}
return nil
}
func (s projectflockService) Resubmit(c *fiber.Ctx, req *validation.Resubmit, id uint) (*entity.ProjectFlock, error) {
if err := s.Validate.Struct(req); err != nil {
return nil, err