Replace status_id with in_progress boolean field

- Remove task_statuses lookup table and StatusID foreign key
- Add InProgress boolean field to Task model
- Add database migration (005_replace_status_with_in_progress)
- Update all handlers, services, and repositories
- Update admin frontend to display in_progress as checkbox/boolean
- Remove Task Statuses tab from admin lookups page
- Update tests to use InProgress instead of StatusID
- Task categorization now uses InProgress for kanban column assignment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-08 20:48:16 -06:00
parent cb250f108b
commit c5b0225422
43 changed files with 353 additions and 753 deletions

View File

@@ -41,9 +41,9 @@ func TestTaskService_CreateTask(t *testing.T) {
resp, err := service.CreateTask(req, user.ID)
require.NoError(t, err)
assert.NotZero(t, resp.ID)
assert.Equal(t, "Fix leaky faucet", resp.Title)
assert.Equal(t, "Kitchen faucet is dripping", resp.Description)
assert.NotZero(t, resp.Data.ID)
assert.Equal(t, "Fix leaky faucet", resp.Data.Title)
assert.Equal(t, "Kitchen faucet is dripping", resp.Data.Description)
}
func TestTaskService_CreateTask_WithOptionalFields(t *testing.T) {
@@ -76,10 +76,10 @@ func TestTaskService_CreateTask_WithOptionalFields(t *testing.T) {
resp, err := service.CreateTask(req, user.ID)
require.NoError(t, err)
assert.NotNil(t, resp.Category)
assert.NotNil(t, resp.Priority)
assert.NotNil(t, resp.DueDate)
assert.NotNil(t, resp.EstimatedCost)
assert.NotNil(t, resp.Data.Category)
assert.NotNil(t, resp.Data.Priority)
assert.NotNil(t, resp.Data.DueDate)
assert.NotNil(t, resp.Data.EstimatedCost)
}
func TestTaskService_CreateTask_AccessDenied(t *testing.T) {
@@ -180,8 +180,8 @@ func TestTaskService_UpdateTask(t *testing.T) {
resp, err := service.UpdateTask(task.ID, user.ID, req)
require.NoError(t, err)
assert.Equal(t, "Updated Title", resp.Title)
assert.Equal(t, "Updated description", resp.Description)
assert.Equal(t, "Updated Title", resp.Data.Title)
assert.Equal(t, "Updated description", resp.Data.Description)
}
func TestTaskService_DeleteTask(t *testing.T) {
@@ -195,7 +195,7 @@ func TestTaskService_DeleteTask(t *testing.T) {
residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
task := testutil.CreateTestTask(t, db, residence.ID, user.ID, "Test Task")
err := service.DeleteTask(task.ID, user.ID)
_, err := service.DeleteTask(task.ID, user.ID)
require.NoError(t, err)
_, err = service.GetTask(task.ID, user.ID)
@@ -215,7 +215,7 @@ func TestTaskService_CancelTask(t *testing.T) {
resp, err := service.CancelTask(task.ID, user.ID)
require.NoError(t, err)
assert.True(t, resp.IsCancelled)
assert.True(t, resp.Data.IsCancelled)
}
func TestTaskService_CancelTask_AlreadyCancelled(t *testing.T) {
@@ -248,7 +248,7 @@ func TestTaskService_UncancelTask(t *testing.T) {
service.CancelTask(task.ID, user.ID)
resp, err := service.UncancelTask(task.ID, user.ID)
require.NoError(t, err)
assert.False(t, resp.IsCancelled)
assert.False(t, resp.Data.IsCancelled)
}
func TestTaskService_ArchiveTask(t *testing.T) {
@@ -264,7 +264,7 @@ func TestTaskService_ArchiveTask(t *testing.T) {
resp, err := service.ArchiveTask(task.ID, user.ID)
require.NoError(t, err)
assert.True(t, resp.IsArchived)
assert.True(t, resp.Data.IsArchived)
}
func TestTaskService_UnarchiveTask(t *testing.T) {
@@ -281,7 +281,7 @@ func TestTaskService_UnarchiveTask(t *testing.T) {
service.ArchiveTask(task.ID, user.ID)
resp, err := service.UnarchiveTask(task.ID, user.ID)
require.NoError(t, err)
assert.False(t, resp.IsArchived)
assert.False(t, resp.Data.IsArchived)
}
func TestTaskService_MarkInProgress(t *testing.T) {
@@ -297,8 +297,7 @@ func TestTaskService_MarkInProgress(t *testing.T) {
resp, err := service.MarkInProgress(task.ID, user.ID)
require.NoError(t, err)
assert.NotNil(t, resp.Status)
assert.Equal(t, "In Progress", resp.Status.Name)
assert.True(t, resp.Data.InProgress)
}
func TestTaskService_CreateCompletion(t *testing.T) {
@@ -319,12 +318,12 @@ func TestTaskService_CreateCompletion(t *testing.T) {
resp, err := service.CreateCompletion(req, user.ID)
require.NoError(t, err)
assert.NotZero(t, resp.ID)
assert.Equal(t, task.ID, resp.TaskID)
assert.Equal(t, "Completed successfully", resp.Notes)
assert.NotZero(t, resp.Data.ID)
assert.Equal(t, task.ID, resp.Data.TaskID)
assert.Equal(t, "Completed successfully", resp.Data.Notes)
}
func TestTaskService_CreateCompletion_RecurringTask_ResetsStatusToPending(t *testing.T) {
func TestTaskService_CreateCompletion_RecurringTask_ResetsInProgress(t *testing.T) {
db := testutil.SetupTestDB(t)
testutil.SeedLookupData(t, db)
taskRepo := repositories.NewTaskRepository(db)
@@ -334,20 +333,16 @@ func TestTaskService_CreateCompletion_RecurringTask_ResetsStatusToPending(t *tes
user := testutil.CreateTestUser(t, db, "owner", "owner@test.com", "password")
residence := testutil.CreateTestResidence(t, db, user.ID, "Test House")
// Get the "In Progress" status (ID=2) and a recurring frequency
var inProgressStatus models.TaskStatus
db.Where("name = ?", "In Progress").First(&inProgressStatus)
var monthlyFrequency models.TaskFrequency
db.Where("name = ?", "Monthly").First(&monthlyFrequency)
// Create a recurring task with "In Progress" status
// Create a recurring task that is in progress
dueDate := time.Now().AddDate(0, 0, 7) // Due in 7 days
task := &models.Task{
ResidenceID: residence.ID,
CreatedByID: user.ID,
Title: "Recurring Task",
StatusID: &inProgressStatus.ID,
InProgress: true,
FrequencyID: &monthlyFrequency.ID,
DueDate: &dueDate,
NextDueDate: &dueDate,
@@ -365,24 +360,21 @@ func TestTaskService_CreateCompletion_RecurringTask_ResetsStatusToPending(t *tes
resp, err := service.CreateCompletion(req, user.ID)
require.NoError(t, err)
assert.NotZero(t, resp.ID)
assert.NotZero(t, resp.Data.ID)
// Verify the task in the response has status reset to "Pending" (ID=1)
require.NotNil(t, resp.Task, "Response should include the updated task")
require.NotNil(t, resp.Task.StatusID, "Task should have a status ID")
assert.Equal(t, uint(1), *resp.Task.StatusID, "Recurring task status should be reset to Pending (ID=1) after completion")
// Verify the task in the response has InProgress reset to false
require.NotNil(t, resp.Data.Task, "Response should include the updated task")
assert.False(t, resp.Data.Task.InProgress, "Recurring task InProgress should be reset to false after completion")
// Verify NextDueDate was updated (should be ~30 days from now for monthly)
require.NotNil(t, resp.Task.NextDueDate, "Recurring task should have NextDueDate set")
require.NotNil(t, resp.Data.Task.NextDueDate, "Recurring task should have NextDueDate set")
expectedNextDue := time.Now().AddDate(0, 0, 30) // Monthly = 30 days
assert.WithinDuration(t, expectedNextDue, *resp.Task.NextDueDate, 24*time.Hour, "NextDueDate should be approximately 30 days from now")
assert.WithinDuration(t, expectedNextDue, *resp.Data.Task.NextDueDate, 24*time.Hour, "NextDueDate should be approximately 30 days from now")
// Also verify by reloading from database directly
var reloadedTask models.Task
db.Preload("Status").First(&reloadedTask, task.ID)
require.NotNil(t, reloadedTask.StatusID)
assert.Equal(t, uint(1), *reloadedTask.StatusID, "Database should show Pending status")
assert.Equal(t, "Pending", reloadedTask.Status.Name)
db.First(&reloadedTask, task.ID)
assert.False(t, reloadedTask.InProgress, "Database should show InProgress=false")
}
func TestTaskService_GetCompletion(t *testing.T) {
@@ -428,7 +420,7 @@ func TestTaskService_DeleteCompletion(t *testing.T) {
}
db.Create(completion)
err := service.DeleteCompletion(completion.ID, user.ID)
_, err := service.DeleteCompletion(completion.ID, user.ID)
require.NoError(t, err)
_, err = service.GetCompletion(completion.ID, user.ID)
@@ -470,18 +462,6 @@ func TestTaskService_GetPriorities(t *testing.T) {
}
}
func TestTaskService_GetStatuses(t *testing.T) {
db := testutil.SetupTestDB(t)
testutil.SeedLookupData(t, db)
taskRepo := repositories.NewTaskRepository(db)
residenceRepo := repositories.NewResidenceRepository(db)
service := NewTaskService(taskRepo, residenceRepo)
statuses, err := service.GetStatuses()
require.NoError(t, err)
assert.Greater(t, len(statuses), 0)
}
func TestTaskService_GetFrequencies(t *testing.T) {
db := testutil.SetupTestDB(t)
testutil.SeedLookupData(t, db)