From 36b0f97897f9d6f4fb676d4e585807b0aa0b45c7 Mon Sep 17 00:00:00 2001 From: giovanni Date: Thu, 2 Apr 2026 11:24:53 +0700 Subject: [PATCH 1/2] fix upser daily checklist status rejected; fix search list daily checklist --- ...ily_checklist_unique_for_rejected.down.sql | 5 ++ ...daily_checklist_unique_for_rejected.up.sql | 6 ++ .../services/daily-checklist.service.go | 73 +++++++++++++++---- 3 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.down.sql create mode 100644 internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.up.sql diff --git a/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.down.sql b/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.down.sql new file mode 100644 index 00000000..1994f220 --- /dev/null +++ b/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.down.sql @@ -0,0 +1,5 @@ +DROP INDEX IF EXISTS idx_daily_checklists_unique_non_rejected; + +ALTER TABLE daily_checklists + ADD CONSTRAINT daily_checklists_date_kandang_category_key + UNIQUE (date, kandang_id, category); diff --git a/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.up.sql b/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.up.sql new file mode 100644 index 00000000..83ea4f41 --- /dev/null +++ b/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.up.sql @@ -0,0 +1,6 @@ +ALTER TABLE daily_checklists + DROP CONSTRAINT IF EXISTS daily_checklists_date_kandang_category_key; + +CREATE UNIQUE INDEX IF NOT EXISTS idx_daily_checklists_unique_non_rejected + ON daily_checklists (date, kandang_id, category) + WHERE (status IS NULL OR status <> 'REJECTED'); diff --git a/internal/modules/daily-checklists/services/daily-checklist.service.go b/internal/modules/daily-checklists/services/daily-checklist.service.go index 6330e641..14937e8b 100644 --- a/internal/modules/daily-checklists/services/daily-checklist.service.go +++ b/internal/modules/daily-checklists/services/daily-checklist.service.go @@ -261,8 +261,11 @@ func (s dailyChecklistService) GetAll(c *fiber.Ctx, params *validation.Query) ([ if params.Search != "" { re := regexp.MustCompile("[^a-zA-Z0-9]") - like := re.ReplaceAll([]byte("%"+params.Search+"%"), []byte("")) - db = db.Where("(regexp_replace(k.name, '[^a-zA-Z0-9]', '', 'g') ILIKE ? OR regexp_replace(dc.category::text, '[^a-zA-Z0-9]', '', 'g') ILIKE ?)", string(like), string(like)) + normalizedSearch := re.ReplaceAllString(params.Search, "") + if normalizedSearch != "" { + like := "%" + normalizedSearch + "%" + db = db.Where("(regexp_replace(k.name, '[^a-zA-Z0-9]', '', 'g') ILIKE ? OR regexp_replace(dc.category::text, '[^a-zA-Z0-9]', '', 'g') ILIKE ?)", like, like) + } } countDB := db.Session(&gorm.Session{}) @@ -504,24 +507,66 @@ func (s *dailyChecklistService) CreateOne(c *fiber.Ctx, req *validation.Create) status := req.Status category := req.Category + targetID := uint(0) - createBody := &entity.DailyChecklist{ - KandangId: req.KandangId, - Date: date, - Category: category, - Status: &status, - } + err = s.Repository.DB().WithContext(c.Context()).Transaction(func(tx *gorm.DB) error { + existing := new(entity.DailyChecklist) + err := tx.Clauses(clause.Locking{Strength: "UPDATE"}). + Where("date = ? AND kandang_id = ? AND category = ? AND (status IS NULL OR status <> ?)", date, req.KandangId, category, "REJECTED"). + Take(existing).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } - err = s.Repository.DB().WithContext(c.Context()).Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "date"}, {Name: "kandang_id"}, {Name: "category"}}, - DoUpdates: clause.Assignments(map[string]any{"updated_at": time.Now()}), - }).Create(createBody).Error + if err == nil { + if err := tx.Model(&entity.DailyChecklist{}). + Where("id = ?", existing.Id). + Update("updated_at", time.Now()).Error; err != nil { + return err + } + + targetID = existing.Id + return nil + } + + createStatus := status + var rejectedCount int64 + if err := tx.Model(&entity.DailyChecklist{}). + Where("date = ? AND kandang_id = ? AND category = ? AND status = ?", date, req.KandangId, category, "REJECTED"). + Count(&rejectedCount).Error; err != nil { + return err + } + if rejectedCount > 0 { + createStatus = "DRAFT" + } + + createBody := &entity.DailyChecklist{ + KandangId: req.KandangId, + Date: date, + Category: category, + Status: &createStatus, + } + + if err := tx.Create(createBody).Error; err != nil { + // Handle concurrent insert for active checklist with same key. + if findErr := tx. + Where("date = ? AND kandang_id = ? AND category = ? AND (status IS NULL OR status <> ?)", date, req.KandangId, category, "REJECTED"). + Take(existing).Error; findErr == nil { + targetID = existing.Id + return nil + } + return err + } + + targetID = createBody.Id + return nil + }) if err != nil { - s.Log.Errorf("Failed to upsert dailyChecklist: %+v", err) + s.Log.Errorf("Failed to create/upsert dailyChecklist: %+v", err) return nil, err } - return s.GetOne(c, createBody.Id) + return s.GetOne(c, targetID) } func (s dailyChecklistService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.DailyChecklist, error) { From 88b6e2f294b01ffd2880207bb88d066f70c3451b Mon Sep 17 00:00:00 2001 From: giovanni Date: Thu, 2 Apr 2026 11:40:38 +0700 Subject: [PATCH 2/2] adjust sql migration --- ...034456_adjust_daily_checklist_unique_for_rejected.down.sql | 4 ++++ ...02034456_adjust_daily_checklist_unique_for_rejected.up.sql | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.down.sql b/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.down.sql index 1994f220..2ef9aecd 100644 --- a/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.down.sql +++ b/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.down.sql @@ -1,5 +1,9 @@ +BEGIN; + DROP INDEX IF EXISTS idx_daily_checklists_unique_non_rejected; ALTER TABLE daily_checklists ADD CONSTRAINT daily_checklists_date_kandang_category_key UNIQUE (date, kandang_id, category); + +COMMIT; diff --git a/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.up.sql b/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.up.sql index 83ea4f41..753deaef 100644 --- a/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.up.sql +++ b/internal/database/migrations/20260402034456_adjust_daily_checklist_unique_for_rejected.up.sql @@ -1,6 +1,10 @@ +BEGIN; + ALTER TABLE daily_checklists DROP CONSTRAINT IF EXISTS daily_checklists_date_kandang_category_key; CREATE UNIQUE INDEX IF NOT EXISTS idx_daily_checklists_unique_non_rejected ON daily_checklists (date, kandang_id, category) WHERE (status IS NULL OR status <> 'REJECTED'); + +COMMIT;