feat/BE/US-76/TASK-122,133,121,120 Recording add create delete edit

This commit is contained in:
ragilap
2025-10-26 15:27:19 +07:00
parent cedd5365d8
commit 8ae614540f
13 changed files with 639 additions and 579 deletions
@@ -28,4 +28,5 @@ func ProjectflockRoutes(v1 fiber.Router, u user.UserService, s projectflock.Proj
route.Get("/kandangs/lookup", ctrl.LookupProjectFlockKandang)
route.Post("/approvals", ctrl.Approval)
route.Get("/flocks/:flock_id/periods", ctrl.GetFlockPeriodSummary)
}
@@ -107,9 +107,14 @@ func (s projectflockService) GetAll(c *fiber.Ctx, params *validation.Query) ([]e
db = db.Where("project_flocks.period = ?", params.Period)
}
if len(params.KandangIds) > 0 {
db = db.Where("EXISTS (SELECT 1 FROM kandangs WHERE kandangs.project_flock_id = project_flocks.id AND kandangs.id IN ?)", params.KandangIds)
db = db.Where(`
EXISTS (
SELECT 1
FROM project_flock_kandangs pfk
WHERE pfk.project_flock_id = project_flocks.id
AND pfk.kandang_id IN ?
)`, params.KandangIds)
}
if params.Search != "" {
normalizedSearch := strings.ToLower(strings.TrimSpace(params.Search))
if normalizedSearch == "" {
@@ -250,10 +255,11 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (*
if len(kandangs) != len(kandangIDs) {
return nil, fiber.NewError(fiber.StatusNotFound, "Some kandangs not found")
}
for _, kandang := range kandangs {
if kandang.ProjectFlockId != nil {
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Kandang %s sudah memiliki project flock", kandang.Name))
}
// larang kalau ada yg sudah terikat ke project lain
if linked, err := s.anyKandangLinkedToOtherProject(c.Context(), s.Repository.DB(), kandangIDs, nil); err != nil {
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate kandangs linkage")
} else if linked {
return nil, fiber.NewError(fiber.StatusConflict, "Beberapa kandang sudah terikat dengan project flock lain")
}
createBody := &entity.ProjectFlock{
@@ -394,11 +400,12 @@ func (s projectflockService) UpdateOne(c *fiber.Ctx, req *validation.Update, id
if len(kandangs) != len(newKandangIDs) {
return nil, fiber.NewError(fiber.StatusNotFound, "Some kandangs not found")
}
for _, k := range kandangs {
if k.ProjectFlockId != nil && *k.ProjectFlockId != id {
return nil, fiber.NewError(fiber.StatusConflict, fmt.Sprintf("Kandang %s sudah terikat dengan project flock lain", k.Name))
}
if linked, err := s.anyKandangLinkedToOtherProject(c.Context(), s.Repository.DB(), newKandangIDs, &id); err != nil {
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate kandangs linkage")
} else if linked {
return nil, fiber.NewError(fiber.StatusConflict, "Beberapa kandang sudah terikat dengan project flock lain")
}
}
hasChanges := hasBodyChanges || hasKandangChanges
@@ -754,7 +761,7 @@ func (s projectflockService) buildOrderExpressions(sortBy, sortOrder string) []s
}
case "kandangs":
return []string{
fmt.Sprintf("(SELECT COUNT(*) FROM kandangs WHERE kandangs.project_flock_id = project_flocks.id) %s", direction),
fmt.Sprintf("(SELECT COUNT(*) FROM project_flock_kandangs pfk WHERE pfk.project_flock_id = project_flocks.id) %s", direction),
fmt.Sprintf("project_flocks.id %s", direction),
}
case "period":
@@ -775,24 +782,50 @@ func (s projectflockService) attachKandangs(ctx context.Context, dbTransaction *
return nil
}
if err := dbTransaction.Model(&entity.Kandang{}).
if err := dbTransaction.
Model(&entity.Kandang{}).
Where("id IN ?", kandangIDs).
Updates(map[string]any{
"project_flock_id": projectFlockID,
"status": string(utils.KandangStatusPengajuan),
"status": string(utils.KandangStatusPengajuan),
}).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update kandangs")
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update kandangs status")
}
pivotRepo := s.pivotRepoWithTx(dbTransaction)
records := make([]*entity.ProjectFlockKandang, len(kandangIDs))
for i, id := range kandangIDs {
records[i] = &entity.ProjectFlockKandang{
ProjectFlockId: projectFlockID,
KandangId: id,
var already []uint
if err := dbTransaction.
Table("project_flock_kandangs").
Where("project_flock_id = ? AND kandang_id IN ?", projectFlockID, kandangIDs).
Pluck("kandang_id", &already).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to check existing pivot")
}
exists := make(map[uint]struct{}, len(already))
for _, id := range already {
exists[id] = struct{}{}
}
var toAttach []uint
seen := make(map[uint]struct{}, len(kandangIDs))
for _, id := range kandangIDs {
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
if _, ok := exists[id]; !ok {
toAttach = append(toAttach, id)
}
}
if err := pivotRepo.CreateMany(ctx, records); err != nil {
if len(toAttach) == 0 {
return nil
}
records := make([]*entity.ProjectFlockKandang, 0, len(toAttach))
for _, id := range toAttach {
records = append(records, &entity.ProjectFlockKandang{
ProjectFlockId: projectFlockID,
KandangId: id,
})
}
if err := s.pivotRepoWithTx(dbTransaction).CreateMany(ctx, records); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to persist project flock history")
}
return nil
@@ -803,15 +836,15 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction *
return nil
}
updates := map[string]any{"project_flock_id": nil}
if resetStatus {
updates["status"] = string(utils.KandangStatusNonActive)
}
if err := dbTransaction.Model(&entity.Kandang{}).
Where("id IN ?", kandangIDs).
Updates(updates).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update kandangs")
if err := dbTransaction.
Model(&entity.Kandang{}).
Where("id IN ?", kandangIDs).
Updates(map[string]any{
"status": string(utils.KandangStatusNonActive),
}).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update kandangs status")
}
}
if err := s.pivotRepoWithTx(dbTransaction).DeleteMany(ctx, projectFlockID, kandangIDs); err != nil {
@@ -820,9 +853,24 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction *
return nil
}
func (s projectflockService) pivotRepoWithTx(dbTransaction *gorm.DB) repository.ProjectFlockKandangRepository {
if s.PivotRepo == nil {
return repository.NewProjectFlockKandangRepository(dbTransaction)
}
return s.PivotRepo.WithTx(dbTransaction)
}
func (s projectflockService) anyKandangLinkedToOtherProject(ctx context.Context, db *gorm.DB, kandangIDs []uint, exceptProjectID *uint) (bool, error) {
q := db.WithContext(ctx).
Table("project_flock_kandangs").
Where("kandang_id IN ?", kandangIDs)
if exceptProjectID != nil {
q = q.Where("project_flock_id <> ?", *exceptProjectID)
}
var count int64
if err := q.Count(&count).Error; err != nil {
return false, err
}
return count > 0, nil
}