mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
adjust validation create daily checklist empty kandang
This commit is contained in:
@@ -127,6 +127,8 @@ const (
|
|||||||
dailyChecklistCategoryEmptyKandang = "empty_kandang"
|
dailyChecklistCategoryEmptyKandang = "empty_kandang"
|
||||||
dailyChecklistStatusRejected = "REJECTED"
|
dailyChecklistStatusRejected = "REJECTED"
|
||||||
dailyChecklistStatusDraft = "DRAFT"
|
dailyChecklistStatusDraft = "DRAFT"
|
||||||
|
dailyChecklistErrEmptyKandangExist = "DailyChecklist cannot be created because empty_kandang already exists for at least one date in range"
|
||||||
|
dailyChecklistErrDateOverlapExist = "DailyChecklist cannot be created because at least one date in range already has a checklist"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewDailyChecklistService(repo repository.DailyChecklistRepository, phaseRepo phaseRepo.PhasesRepository, validate *validator.Validate, documentSvc commonSvc.DocumentService) DailyChecklistService {
|
func NewDailyChecklistService(repo repository.DailyChecklistRepository, phaseRepo phaseRepo.PhasesRepository, validate *validator.Validate, documentSvc commonSvc.DocumentService) DailyChecklistService {
|
||||||
@@ -538,10 +540,21 @@ func (s *dailyChecklistService) CreateOne(c *fiber.Ctx, req *validation.Create)
|
|||||||
targetID := uint(0)
|
targetID := uint(0)
|
||||||
|
|
||||||
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(tx *gorm.DB) error {
|
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(tx *gorm.DB) error {
|
||||||
|
if err := s.lockKandangForChecklistCreation(tx, req.KandangId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if req.EmptyKandang {
|
if req.EmptyKandang {
|
||||||
|
if err := s.validateNoChecklistOverlapForEmptyKandang(tx, req.KandangId, date, endDate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return s.createBulkDailyChecklists(tx, req.KandangId, date, endDate, category, status, &targetID)
|
return s.createBulkDailyChecklists(tx, req.KandangId, date, endDate, category, status, &targetID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.validateNoEmptyKandangConflict(tx, req.KandangId, date, endDate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return s.createOrReuseSingleDailyChecklist(tx, req.KandangId, date, category, status, &targetID)
|
return s.createOrReuseSingleDailyChecklist(tx, req.KandangId, date, category, status, &targetID)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -552,6 +565,56 @@ func (s *dailyChecklistService) CreateOne(c *fiber.Ctx, req *validation.Create)
|
|||||||
return s.GetOne(c, targetID)
|
return s.GetOne(c, targetID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *dailyChecklistService) lockKandangForChecklistCreation(tx *gorm.DB, kandangID uint) error {
|
||||||
|
if kandangID == 0 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid kandang id")
|
||||||
|
}
|
||||||
|
|
||||||
|
var lockedKandangID uint
|
||||||
|
query := tx.Table("kandang_groups").Select("id").Where("id = ?", kandangID)
|
||||||
|
if tx.Dialector.Name() != "sqlite" {
|
||||||
|
query = query.Clauses(clause.Locking{Strength: "UPDATE"})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := query.Take(&lockedKandangID).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return fiber.NewError(fiber.StatusNotFound, "Kandang not found")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dailyChecklistService) validateNoChecklistOverlapForEmptyKandang(tx *gorm.DB, kandangID uint, startDate, endDate time.Time) error {
|
||||||
|
var conflictCount int64
|
||||||
|
if err := tx.Model(&entity.DailyChecklist{}).
|
||||||
|
Where("kandang_id = ? AND date BETWEEN ? AND ? AND deleted_at IS NULL", kandangID, startDate, endDate).
|
||||||
|
Count(&conflictCount).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if conflictCount > 0 {
|
||||||
|
return fiber.NewError(fiber.StatusConflict, dailyChecklistErrDateOverlapExist)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *dailyChecklistService) validateNoEmptyKandangConflict(tx *gorm.DB, kandangID uint, startDate, endDate time.Time) error {
|
||||||
|
var conflictCount int64
|
||||||
|
if err := tx.Model(&entity.DailyChecklist{}).
|
||||||
|
Where("kandang_id = ? AND date BETWEEN ? AND ? AND category = ? AND deleted_at IS NULL", kandangID, startDate, endDate, dailyChecklistCategoryEmptyKandang).
|
||||||
|
Count(&conflictCount).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if conflictCount > 0 {
|
||||||
|
return fiber.NewError(fiber.StatusConflict, dailyChecklistErrEmptyKandangExist)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *dailyChecklistService) createOrReuseSingleDailyChecklist(tx *gorm.DB, kandangID uint, date time.Time, category, status string, targetID *uint) error {
|
func (s *dailyChecklistService) createOrReuseSingleDailyChecklist(tx *gorm.DB, kandangID uint, date time.Time, category, status string, targetID *uint) error {
|
||||||
existing := new(entity.DailyChecklist)
|
existing := new(entity.DailyChecklist)
|
||||||
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||||
|
|||||||
@@ -0,0 +1,409 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/glebarez/sqlite"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/repositories"
|
||||||
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/daily-checklists/validations"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateOneRejectsWhenSameDateHasActiveEmptyKandang(t *testing.T) {
|
||||||
|
svc, db := setupDailyChecklistServiceTest(t)
|
||||||
|
|
||||||
|
insertDailyChecklistRow(t, db, 1, mustDate(t, "2026-01-10"), dailyChecklistCategoryEmptyKandang, strPtr("DRAFT"), nil)
|
||||||
|
|
||||||
|
result, serviceErr, resp := runCreateOneRequest(t, svc, &validation.Create{
|
||||||
|
Date: "2026-01-10",
|
||||||
|
KandangId: 1,
|
||||||
|
Category: "cleaning",
|
||||||
|
Status: "DRAFT",
|
||||||
|
})
|
||||||
|
|
||||||
|
if result != nil {
|
||||||
|
t.Fatalf("expected nil result, got %+v", result)
|
||||||
|
}
|
||||||
|
assertFiberErrorCode(t, serviceErr, fiber.StatusConflict)
|
||||||
|
if resp.StatusCode != fiber.StatusConflict {
|
||||||
|
t.Fatalf("expected HTTP status %d, got %d", fiber.StatusConflict, resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateOneRejectsWhenSameDateHasRejectedEmptyKandang(t *testing.T) {
|
||||||
|
svc, db := setupDailyChecklistServiceTest(t)
|
||||||
|
|
||||||
|
insertDailyChecklistRow(t, db, 1, mustDate(t, "2026-01-10"), dailyChecklistCategoryEmptyKandang, strPtr(dailyChecklistStatusRejected), nil)
|
||||||
|
|
||||||
|
result, serviceErr, resp := runCreateOneRequest(t, svc, &validation.Create{
|
||||||
|
Date: "2026-01-10",
|
||||||
|
KandangId: 1,
|
||||||
|
Category: "cleaning",
|
||||||
|
Status: "DRAFT",
|
||||||
|
})
|
||||||
|
|
||||||
|
if result != nil {
|
||||||
|
t.Fatalf("expected nil result, got %+v", result)
|
||||||
|
}
|
||||||
|
assertFiberErrorCode(t, serviceErr, fiber.StatusConflict)
|
||||||
|
if resp.StatusCode != fiber.StatusConflict {
|
||||||
|
t.Fatalf("expected HTTP status %d, got %d", fiber.StatusConflict, resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateOneAllowsWhenOnlySoftDeletedEmptyKandangExists(t *testing.T) {
|
||||||
|
svc, db := setupDailyChecklistServiceTest(t)
|
||||||
|
|
||||||
|
deletedAt := mustDateTime(t, "2026-01-11 10:00:00")
|
||||||
|
insertDailyChecklistRow(t, db, 1, mustDate(t, "2026-01-10"), dailyChecklistCategoryEmptyKandang, strPtr("DRAFT"), &deletedAt)
|
||||||
|
|
||||||
|
result, serviceErr, resp := runCreateOneRequest(t, svc, &validation.Create{
|
||||||
|
Date: "2026-01-10",
|
||||||
|
KandangId: 1,
|
||||||
|
Category: "cleaning",
|
||||||
|
Status: "DRAFT",
|
||||||
|
})
|
||||||
|
|
||||||
|
if serviceErr != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", serviceErr)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != fiber.StatusCreated {
|
||||||
|
t.Fatalf("expected HTTP status %d, got %d", fiber.StatusCreated, resp.StatusCode)
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
t.Fatal("expected non-nil result")
|
||||||
|
}
|
||||||
|
if result.Category != "cleaning" {
|
||||||
|
t.Fatalf("expected category cleaning, got %s", result.Category)
|
||||||
|
}
|
||||||
|
|
||||||
|
var activeCount int64
|
||||||
|
if err := db.Model(&entity.DailyChecklist{}).
|
||||||
|
Where("kandang_id = ? AND date = ? AND category = ? AND deleted_at IS NULL", 1, mustDate(t, "2026-01-10"), "cleaning").
|
||||||
|
Count(&activeCount).Error; err != nil {
|
||||||
|
t.Fatalf("failed counting active checklists: %v", err)
|
||||||
|
}
|
||||||
|
if activeCount != 1 {
|
||||||
|
t.Fatalf("expected 1 active cleaning checklist, got %d", activeCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateOneRejectsBulkEmptyKandangWhenDateRangeHasConflict(t *testing.T) {
|
||||||
|
svc, db := setupDailyChecklistServiceTest(t)
|
||||||
|
|
||||||
|
insertDailyChecklistRow(t, db, 1, mustDate(t, "2026-01-03"), dailyChecklistCategoryEmptyKandang, strPtr("APPROVED"), nil)
|
||||||
|
|
||||||
|
result, serviceErr, resp := runCreateOneRequest(t, svc, &validation.Create{
|
||||||
|
Date: "2026-01-01",
|
||||||
|
KandangId: 1,
|
||||||
|
Category: "cleaning",
|
||||||
|
Status: "DRAFT",
|
||||||
|
EmptyKandang: true,
|
||||||
|
EmptyKandangEndDate: "2026-01-05",
|
||||||
|
})
|
||||||
|
|
||||||
|
if result != nil {
|
||||||
|
t.Fatalf("expected nil result, got %+v", result)
|
||||||
|
}
|
||||||
|
assertFiberErrorCode(t, serviceErr, fiber.StatusConflict)
|
||||||
|
if resp.StatusCode != fiber.StatusConflict {
|
||||||
|
t.Fatalf("expected HTTP status %d, got %d", fiber.StatusConflict, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
var activeInRange int64
|
||||||
|
if err := db.Model(&entity.DailyChecklist{}).
|
||||||
|
Where("kandang_id = ? AND date BETWEEN ? AND ? AND deleted_at IS NULL", 1, mustDate(t, "2026-01-01"), mustDate(t, "2026-01-05")).
|
||||||
|
Count(&activeInRange).Error; err != nil {
|
||||||
|
t.Fatalf("failed counting checklists in range: %v", err)
|
||||||
|
}
|
||||||
|
if activeInRange != 1 {
|
||||||
|
t.Fatalf("expected only pre-existing row to remain in range, got %d rows", activeInRange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateOneRejectsBulkEmptyKandangWhenRangeHasNonEmptyChecklist(t *testing.T) {
|
||||||
|
svc, db := setupDailyChecklistServiceTest(t)
|
||||||
|
|
||||||
|
insertDailyChecklistRow(t, db, 1, mustDate(t, "2026-01-03"), "cleaning", strPtr("APPROVED"), nil)
|
||||||
|
|
||||||
|
result, serviceErr, resp := runCreateOneRequest(t, svc, &validation.Create{
|
||||||
|
Date: "2026-01-01",
|
||||||
|
KandangId: 1,
|
||||||
|
Category: "cleaning",
|
||||||
|
Status: "DRAFT",
|
||||||
|
EmptyKandang: true,
|
||||||
|
EmptyKandangEndDate: "2026-01-05",
|
||||||
|
})
|
||||||
|
|
||||||
|
if result != nil {
|
||||||
|
t.Fatalf("expected nil result, got %+v", result)
|
||||||
|
}
|
||||||
|
assertFiberErrorCode(t, serviceErr, fiber.StatusConflict)
|
||||||
|
if resp.StatusCode != fiber.StatusConflict {
|
||||||
|
t.Fatalf("expected HTTP status %d, got %d", fiber.StatusConflict, resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateOneRejectsBulkEmptyKandangWhenRangeHasRejectedChecklist(t *testing.T) {
|
||||||
|
svc, db := setupDailyChecklistServiceTest(t)
|
||||||
|
|
||||||
|
insertDailyChecklistRow(t, db, 1, mustDate(t, "2026-01-03"), "cleaning", strPtr(dailyChecklistStatusRejected), nil)
|
||||||
|
|
||||||
|
result, serviceErr, resp := runCreateOneRequest(t, svc, &validation.Create{
|
||||||
|
Date: "2026-01-01",
|
||||||
|
KandangId: 1,
|
||||||
|
Category: "cleaning",
|
||||||
|
Status: "DRAFT",
|
||||||
|
EmptyKandang: true,
|
||||||
|
EmptyKandangEndDate: "2026-01-05",
|
||||||
|
})
|
||||||
|
|
||||||
|
if result != nil {
|
||||||
|
t.Fatalf("expected nil result, got %+v", result)
|
||||||
|
}
|
||||||
|
assertFiberErrorCode(t, serviceErr, fiber.StatusConflict)
|
||||||
|
if resp.StatusCode != fiber.StatusConflict {
|
||||||
|
t.Fatalf("expected HTTP status %d, got %d", fiber.StatusConflict, resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateOneAllowsBulkEmptyKandangWhenRangeHasOnlySoftDeletedChecklist(t *testing.T) {
|
||||||
|
svc, db := setupDailyChecklistServiceTest(t)
|
||||||
|
|
||||||
|
deletedAt := mustDateTime(t, "2026-01-11 10:00:00")
|
||||||
|
insertDailyChecklistRow(t, db, 1, mustDate(t, "2026-01-03"), "cleaning", strPtr("APPROVED"), &deletedAt)
|
||||||
|
|
||||||
|
result, serviceErr, resp := runCreateOneRequest(t, svc, &validation.Create{
|
||||||
|
Date: "2026-01-01",
|
||||||
|
KandangId: 1,
|
||||||
|
Category: "cleaning",
|
||||||
|
Status: "DRAFT",
|
||||||
|
EmptyKandang: true,
|
||||||
|
EmptyKandangEndDate: "2026-01-05",
|
||||||
|
})
|
||||||
|
|
||||||
|
if serviceErr != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", serviceErr)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != fiber.StatusCreated {
|
||||||
|
t.Fatalf("expected HTTP status %d, got %d", fiber.StatusCreated, resp.StatusCode)
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
t.Fatal("expected non-nil result")
|
||||||
|
}
|
||||||
|
if result.Category != dailyChecklistCategoryEmptyKandang {
|
||||||
|
t.Fatalf("expected category %s, got %s", dailyChecklistCategoryEmptyKandang, result.Category)
|
||||||
|
}
|
||||||
|
|
||||||
|
var activeInRange int64
|
||||||
|
if err := db.Model(&entity.DailyChecklist{}).
|
||||||
|
Where("kandang_id = ? AND date BETWEEN ? AND ? AND deleted_at IS NULL", 1, mustDate(t, "2026-01-01"), mustDate(t, "2026-01-05")).
|
||||||
|
Count(&activeInRange).Error; err != nil {
|
||||||
|
t.Fatalf("failed counting checklists in range: %v", err)
|
||||||
|
}
|
||||||
|
if activeInRange != 5 {
|
||||||
|
t.Fatalf("expected 5 active checklists created for range, got %d", activeInRange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateOneReusesExistingChecklistWhenNoEmptyKandangConflict(t *testing.T) {
|
||||||
|
svc, db := setupDailyChecklistServiceTest(t)
|
||||||
|
|
||||||
|
existingID := insertDailyChecklistRow(t, db, 1, mustDate(t, "2026-01-10"), "cleaning", strPtr("APPROVED"), nil)
|
||||||
|
|
||||||
|
result, serviceErr, resp := runCreateOneRequest(t, svc, &validation.Create{
|
||||||
|
Date: "2026-01-10",
|
||||||
|
KandangId: 1,
|
||||||
|
Category: "cleaning",
|
||||||
|
Status: "DRAFT",
|
||||||
|
})
|
||||||
|
|
||||||
|
if serviceErr != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", serviceErr)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != fiber.StatusCreated {
|
||||||
|
t.Fatalf("expected HTTP status %d, got %d", fiber.StatusCreated, resp.StatusCode)
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
t.Fatal("expected non-nil result")
|
||||||
|
}
|
||||||
|
if result.Id != existingID {
|
||||||
|
t.Fatalf("expected existing checklist id %d to be reused, got %d", existingID, result.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
var activeCount int64
|
||||||
|
if err := db.Model(&entity.DailyChecklist{}).
|
||||||
|
Where("kandang_id = ? AND date = ? AND category = ? AND deleted_at IS NULL", 1, mustDate(t, "2026-01-10"), "cleaning").
|
||||||
|
Count(&activeCount).Error; err != nil {
|
||||||
|
t.Fatalf("failed counting active checklists: %v", err)
|
||||||
|
}
|
||||||
|
if activeCount != 1 {
|
||||||
|
t.Fatalf("expected 1 active cleaning checklist, got %d", activeCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupDailyChecklistServiceTest(t *testing.T) (DailyChecklistService, *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 areas (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
created_by INTEGER NOT NULL,
|
||||||
|
created_at DATETIME NULL,
|
||||||
|
updated_at DATETIME NULL,
|
||||||
|
deleted_at DATETIME NULL
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE locations (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
area_id INTEGER NOT NULL,
|
||||||
|
created_by INTEGER NOT NULL,
|
||||||
|
created_at DATETIME NULL,
|
||||||
|
updated_at DATETIME NULL,
|
||||||
|
deleted_at DATETIME NULL
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE kandang_groups (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
location_id INTEGER NOT NULL,
|
||||||
|
pic_id INTEGER NOT NULL,
|
||||||
|
created_by INTEGER NOT NULL,
|
||||||
|
created_at DATETIME NULL,
|
||||||
|
updated_at DATETIME NULL,
|
||||||
|
deleted_at DATETIME NULL
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE daily_checklists (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
kandang_id INTEGER NOT NULL,
|
||||||
|
checklist_id INTEGER NULL,
|
||||||
|
date DATE NOT NULL,
|
||||||
|
name TEXT NULL,
|
||||||
|
status TEXT NULL,
|
||||||
|
category TEXT NOT NULL,
|
||||||
|
total_score INTEGER NULL,
|
||||||
|
document_path TEXT NULL,
|
||||||
|
reject_reason TEXT NULL,
|
||||||
|
created_by INTEGER NULL,
|
||||||
|
deleted_by INTEGER NULL,
|
||||||
|
created_at DATETIME NULL,
|
||||||
|
updated_at DATETIME NULL,
|
||||||
|
deleted_at DATETIME NULL
|
||||||
|
)`,
|
||||||
|
`INSERT INTO areas (id, name, created_by, created_at, updated_at, deleted_at) VALUES (1, 'Area A', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL)`,
|
||||||
|
`INSERT INTO locations (id, name, address, area_id, created_by, created_at, updated_at, deleted_at) VALUES (1, 'Farm A', 'Address', 1, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL)`,
|
||||||
|
`INSERT INTO kandang_groups (id, name, status, location_id, pic_id, created_by, created_at, updated_at, deleted_at) VALUES (1, 'Kandang A', 'ACTIVE', 1, 1, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL)`,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, stmt := range statements {
|
||||||
|
if err := db.Exec(stmt).Error; err != nil {
|
||||||
|
t.Fatalf("failed preparing schema: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repo := repository.NewDailyChecklistRepository(db)
|
||||||
|
svc := NewDailyChecklistService(repo, nil, validator.New(), nil)
|
||||||
|
return svc, db
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCreateOneRequest(t *testing.T, svc DailyChecklistService, req *validation.Create) (*entity.DailyChecklist, error, *http.Response) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
app := fiber.New()
|
||||||
|
var (
|
||||||
|
result *entity.DailyChecklist
|
||||||
|
serviceErr error
|
||||||
|
)
|
||||||
|
|
||||||
|
app.Post("/", func(c *fiber.Ctx) error {
|
||||||
|
result, serviceErr = svc.CreateOne(c, req)
|
||||||
|
if serviceErr != nil {
|
||||||
|
return serviceErr
|
||||||
|
}
|
||||||
|
return c.SendStatus(fiber.StatusCreated)
|
||||||
|
})
|
||||||
|
|
||||||
|
resp, err := app.Test(httptest.NewRequest(http.MethodPost, "/", nil))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed running fiber request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, serviceErr, resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertDailyChecklistRow(t *testing.T, db *gorm.DB, kandangID uint, date time.Time, category string, status *string, deletedAt *time.Time) uint {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
row := &entity.DailyChecklist{
|
||||||
|
KandangId: kandangID,
|
||||||
|
Date: date,
|
||||||
|
Category: category,
|
||||||
|
Status: status,
|
||||||
|
}
|
||||||
|
if deletedAt != nil {
|
||||||
|
row.DeletedAt = gorm.DeletedAt{
|
||||||
|
Time: *deletedAt,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Create(row).Error; err != nil {
|
||||||
|
t.Fatalf("failed inserting daily checklist row: %v", err)
|
||||||
|
}
|
||||||
|
return row.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertFiberErrorCode(t *testing.T, err error, expectedCode int) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
var fiberErr *fiber.Error
|
||||||
|
if !errors.As(err, &fiberErr) {
|
||||||
|
t.Fatalf("expected *fiber.Error, got %T (%v)", err, err)
|
||||||
|
}
|
||||||
|
if fiberErr.Code != expectedCode {
|
||||||
|
t.Fatalf("expected fiber error code %d, got %d", expectedCode, fiberErr.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustDate(t *testing.T, raw string) time.Time {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
value, err := time.Parse(dailyChecklistDateLayout, raw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed parsing date %q: %v", raw, err)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustDateTime(t *testing.T, raw string) time.Time {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
value, err := time.Parse("2006-01-02 15:04:05", raw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed parsing datetime %q: %v", raw, err)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func strPtr(value string) *string {
|
||||||
|
v := value
|
||||||
|
return &v
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user