diff --git a/backend/app/api/handlers/v1/v1_ctrl_maint_entry.go b/backend/app/api/handlers/v1/v1_ctrl_maint_entry.go index 63c8fb6d..e9f1f97c 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_maint_entry.go +++ b/backend/app/api/handlers/v1/v1_ctrl_maint_entry.go @@ -15,13 +15,14 @@ import ( // @Summary Get Maintenance Log // @Tags Item Maintenance // @Produce json -// @Success 200 {object} repo.MaintenanceLog +// @Param filters query repo.MaintenanceFilters false "which maintenance to retrieve" +// @Success 200 {array} repo.MaintenanceEntryWithDetails[] // @Router /v1/items/{id}/maintenance [GET] // @Security Bearer func (ctrl *V1Controller) HandleMaintenanceLogGet() errchain.HandlerFunc { - fn := func(r *http.Request, ID uuid.UUID, q repo.MaintenanceLogQuery) (repo.MaintenanceLog, error) { + fn := func(r *http.Request, ID uuid.UUID, filters repo.MaintenanceFilters) ([]repo.MaintenanceEntryWithDetails, error) { auth := services.NewContext(r.Context()) - return ctrl.repo.MaintEntry.GetLog(auth, auth.GID, ID, q) + return ctrl.repo.MaintEntry.GetMaintenanceByItemID(auth, auth.GID, ID, filters) } return adapters.QueryID("id", fn, http.StatusOK) diff --git a/backend/app/api/static/docs/docs.go b/backend/app/api/static/docs/docs.go index 7fef44b3..e72b0e56 100644 --- a/backend/app/api/static/docs/docs.go +++ b/backend/app/api/static/docs/docs.go @@ -920,11 +920,31 @@ const docTemplate = `{ "Item Maintenance" ], "summary": "Get Maintenance Log", + "parameters": [ + { + "enum": [ + "scheduled", + "completed", + "both" + ], + "type": "string", + "x-enum-varnames": [ + "MaintenanceFilterStatusScheduled", + "MaintenanceFilterStatusCompleted", + "MaintenanceFilterStatusBoth" + ], + "name": "status", + "in": "query" + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/repo.MaintenanceLog" + "type": "array", + "items": { + "$ref": "#/definitions/repo.MaintenanceEntryWithDetails" + } } } } @@ -2701,26 +2721,6 @@ const docTemplate = `{ "MaintenanceFilterStatusBoth" ] }, - "repo.MaintenanceLog": { - "type": "object", - "properties": { - "costAverage": { - "type": "number" - }, - "costTotal": { - "type": "number" - }, - "entries": { - "type": "array", - "items": { - "$ref": "#/definitions/repo.MaintenanceEntry" - } - }, - "itemId": { - "type": "string" - } - } - }, "repo.NotifierCreate": { "type": "object", "required": [ diff --git a/backend/app/api/static/docs/swagger.json b/backend/app/api/static/docs/swagger.json index 6c642d8d..4601140a 100644 --- a/backend/app/api/static/docs/swagger.json +++ b/backend/app/api/static/docs/swagger.json @@ -913,11 +913,31 @@ "Item Maintenance" ], "summary": "Get Maintenance Log", + "parameters": [ + { + "enum": [ + "scheduled", + "completed", + "both" + ], + "type": "string", + "x-enum-varnames": [ + "MaintenanceFilterStatusScheduled", + "MaintenanceFilterStatusCompleted", + "MaintenanceFilterStatusBoth" + ], + "name": "status", + "in": "query" + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/repo.MaintenanceLog" + "type": "array", + "items": { + "$ref": "#/definitions/repo.MaintenanceEntryWithDetails" + } } } } @@ -2694,26 +2714,6 @@ "MaintenanceFilterStatusBoth" ] }, - "repo.MaintenanceLog": { - "type": "object", - "properties": { - "costAverage": { - "type": "number" - }, - "costTotal": { - "type": "number" - }, - "entries": { - "type": "array", - "items": { - "$ref": "#/definitions/repo.MaintenanceEntry" - } - }, - "itemId": { - "type": "string" - } - } - }, "repo.NotifierCreate": { "type": "object", "required": [ diff --git a/backend/app/api/static/docs/swagger.yaml b/backend/app/api/static/docs/swagger.yaml index d6275708..6c2d5222 100644 --- a/backend/app/api/static/docs/swagger.yaml +++ b/backend/app/api/static/docs/swagger.yaml @@ -511,19 +511,6 @@ definitions: - MaintenanceFilterStatusScheduled - MaintenanceFilterStatusCompleted - MaintenanceFilterStatusBoth - repo.MaintenanceLog: - properties: - costAverage: - type: number - costTotal: - type: number - entries: - items: - $ref: '#/definitions/repo.MaintenanceEntry' - type: array - itemId: - type: string - type: object repo.NotifierCreate: properties: isActive: @@ -1249,13 +1236,27 @@ paths: - Items Attachments /v1/items/{id}/maintenance: get: + parameters: + - enum: + - scheduled + - completed + - both + in: query + name: status + type: string + x-enum-varnames: + - MaintenanceFilterStatusScheduled + - MaintenanceFilterStatusCompleted + - MaintenanceFilterStatusBoth produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/repo.MaintenanceLog' + items: + $ref: '#/definitions/repo.MaintenanceEntryWithDetails' + type: array security: - Bearer: [] summary: Get Maintenance Log diff --git a/backend/internal/data/repo/repo_maintenance_entry.go b/backend/internal/data/repo/repo_maintenance_entry.go index 565ed0f8..6f5c135b 100644 --- a/backend/internal/data/repo/repo_maintenance_entry.go +++ b/backend/internal/data/repo/repo_maintenance_entry.go @@ -59,13 +59,6 @@ type ( Description string `json:"description"` Cost float64 `json:"cost,string"` } - - MaintenanceLog struct { - ItemID uuid.UUID `json:"itemId"` - CostAverage float64 `json:"costAverage"` - CostTotal float64 `json:"costTotal"` - Entries []MaintenanceEntry `json:"entries"` - } ) var ( @@ -130,76 +123,32 @@ func (r *MaintenanceEntryRepository) Update(ctx context.Context, id uuid.UUID, i return mapMaintenanceEntryErr(item, err) } -type MaintenanceLogQuery struct { - Completed bool `json:"completed" schema:"completed"` - Scheduled bool `json:"scheduled" schema:"scheduled"` -} - -func (r *MaintenanceEntryRepository) GetLog(ctx context.Context, groupID, itemID uuid.UUID, query MaintenanceLogQuery) (MaintenanceLog, error) { - log := MaintenanceLog{ - ItemID: itemID, - } - - q := r.db.MaintenanceEntry.Query().Where( +func (r *MaintenanceEntryRepository) GetMaintenanceByItemID(ctx context.Context, groupID, itemID uuid.UUID, filters MaintenanceFilters) ([]MaintenanceEntryWithDetails, error) { + query := r.db.MaintenanceEntry.Query().Where( maintenanceentry.ItemID(itemID), maintenanceentry.HasItemWith( item.HasGroupWith(group.IDEQ(groupID)), ), ) - - if query.Completed { - q = q.Where(maintenanceentry.And( - maintenanceentry.DateNotNil(), - maintenanceentry.DateNEQ(time.Time{}), + if filters.Status == MaintenanceFilterStatusScheduled { + query = query.Where(maintenanceentry.Or( + maintenanceentry.DateIsNil(), + maintenanceentry.DateEQ(time.Time{}), )) - } else if query.Scheduled { - q = q.Where(maintenanceentry.And( - maintenanceentry.Or( + } else if filters.Status == MaintenanceFilterStatusCompleted { + query = query.Where( + maintenanceentry.Not(maintenanceentry.Or( maintenanceentry.DateIsNil(), - maintenanceentry.DateEQ(time.Time{}), - ), - maintenanceentry.ScheduledDateNotNil(), - maintenanceentry.ScheduledDateNEQ(time.Time{}), - )) + maintenanceentry.DateEQ(time.Time{})), + )) } + entries, err := query.WithItem().Order(maintenanceentry.ByScheduledDate()).All(ctx) - entries, err := q.Order(ent.Desc(maintenanceentry.FieldDate)). - All(ctx) if err != nil { - return MaintenanceLog{}, err + return []MaintenanceEntryWithDetails{}, err } - log.Entries = mapEachMaintenanceEntry(entries) - - var maybeTotal *float64 - var maybeAverage *float64 - - statement := ` -SELECT - SUM(cost_total) AS total_of_totals, - AVG(cost_total) AS avg_of_averages -FROM - ( - SELECT - strftime('%m-%Y', date) AS my, - SUM(cost) AS cost_total - FROM - maintenance_entries - WHERE - item_id = ? - GROUP BY - my - )` - - row := r.db.Sql().QueryRowContext(ctx, statement, itemID) - err = row.Scan(&maybeTotal, &maybeAverage) - if err != nil { - return MaintenanceLog{}, err - } - - log.CostAverage = orDefault(maybeAverage, 0) - log.CostTotal = orDefault(maybeTotal, 0) - return log, nil + return mapEachMaintenanceEntryWithDetails(entries), nil } func (r *MaintenanceEntryRepository) Delete(ctx context.Context, id uuid.UUID) error { diff --git a/backend/internal/data/repo/repo_maintenance_entry_test.go b/backend/internal/data/repo/repo_maintenance_entry_test.go index 0c101ab1..6f6bc0fd 100644 --- a/backend/internal/data/repo/repo_maintenance_entry_test.go +++ b/backend/internal/data/repo/repo_maintenance_entry_test.go @@ -60,27 +60,14 @@ func TestMaintenanceEntryRepository_GetLog(t *testing.T) { } // Get the log for the item - log, err := tRepos.MaintEntry.GetLog(context.Background(), tGroup.ID, item.ID, MaintenanceLogQuery{ - Completed: true, - }) + log, err := tRepos.MaintEntry.GetMaintenanceByItemID(context.Background(), tGroup.ID, item.ID, MaintenanceFilters{Status: MaintenanceFilterStatusCompleted}) if err != nil { t.Fatalf("failed to get maintenance log: %v", err) } - assert.Equal(t, item.ID, log.ItemID) - assert.Len(t, log.Entries, 10) + assert.Len(t, log, 10) - // Calculate the average cost - var total float64 - - for _, entry := range log.Entries { - total += entry.Cost - } - - assert.InDelta(t, total, log.CostTotal, .001, "total cost should be equal to the sum of all entries") - assert.InDelta(t, total/2, log.CostAverage, 001, "average cost should be the average of the two months") - - for _, entry := range log.Entries { + for _, entry := range log { err := tRepos.MaintEntry.Delete(context.Background(), entry.ID) require.NoError(t, err) } diff --git a/docs/docs/api/openapi-2.0.json b/docs/docs/api/openapi-2.0.json index 6c642d8d..4601140a 100644 --- a/docs/docs/api/openapi-2.0.json +++ b/docs/docs/api/openapi-2.0.json @@ -913,11 +913,31 @@ "Item Maintenance" ], "summary": "Get Maintenance Log", + "parameters": [ + { + "enum": [ + "scheduled", + "completed", + "both" + ], + "type": "string", + "x-enum-varnames": [ + "MaintenanceFilterStatusScheduled", + "MaintenanceFilterStatusCompleted", + "MaintenanceFilterStatusBoth" + ], + "name": "status", + "in": "query" + } + ], "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/repo.MaintenanceLog" + "type": "array", + "items": { + "$ref": "#/definitions/repo.MaintenanceEntryWithDetails" + } } } } @@ -2694,26 +2714,6 @@ "MaintenanceFilterStatusBoth" ] }, - "repo.MaintenanceLog": { - "type": "object", - "properties": { - "costAverage": { - "type": "number" - }, - "costTotal": { - "type": "number" - }, - "entries": { - "type": "array", - "items": { - "$ref": "#/definitions/repo.MaintenanceEntry" - } - }, - "itemId": { - "type": "string" - } - } - }, "repo.NotifierCreate": { "type": "object", "required": [ diff --git a/frontend/components/Maintenance/EditModal.vue b/frontend/components/Maintenance/EditModal.vue index 8176bbe5..5773aeda 100644 --- a/frontend/components/Maintenance/EditModal.vue +++ b/frontend/components/Maintenance/EditModal.vue @@ -136,7 +136,7 @@ } async function complete(maintenanceEntry: MaintenanceEntry) { - const { error } = await api.maintenances.update(maintenanceEntry.id, { + const { error } = await api.maintenance.update(maintenanceEntry.id, { name: maintenanceEntry.name, completedDate: new Date(Date.now()), scheduledDate: maintenanceEntry.scheduledDate ?? "null", @@ -144,7 +144,7 @@ cost: maintenanceEntry.cost, }); if (error) { - toast.error(t("maintenances.toast.failed_to_update")); + toast.error(t("maintenance.toast.failed_to_update")); } emit("changed"); } diff --git a/frontend/lib/api/types/data-contracts.ts b/frontend/lib/api/types/data-contracts.ts index 12727f0f..62c1286f 100644 --- a/frontend/lib/api/types/data-contracts.ts +++ b/frontend/lib/api/types/data-contracts.ts @@ -306,13 +306,6 @@ export enum MaintenanceFilterStatus { MaintenanceFilterStatusBoth = "both", } -export interface MaintenanceLog { - costAverage: number; - costTotal: number; - entries: MaintenanceEntry[]; - itemId: string; -} - export interface NotifierCreate { isActive: boolean; /** diff --git a/frontend/pages/maintenance.vue b/frontend/pages/maintenance.vue index 60b05169..f566402f 100644 --- a/frontend/pages/maintenance.vue +++ b/frontend/pages/maintenance.vue @@ -127,7 +127,7 @@ - {{ $t("maintenances.list.complete") }} + {{ $t("maintenance.list.complete") }} - {{ $t("maintenances.list.complete_and_duplicate") }} + {{ $t("maintenance.list.complete_and_duplicate") }}