Skip to content

Commit 32b3361

Browse files
committed
Add Appointment model and integrate with Operation
1 parent be93139 commit 32b3361

File tree

4 files changed

+80
-2
lines changed

4 files changed

+80
-2
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.ctrlhub.core.projects.appointments.response
2+
3+
import com.fasterxml.jackson.annotation.JsonCreator
4+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
5+
import com.fasterxml.jackson.annotation.JsonProperty
6+
import com.github.jasminb.jsonapi.StringIdHandler
7+
import com.github.jasminb.jsonapi.annotations.Id
8+
import com.github.jasminb.jsonapi.annotations.Type
9+
10+
@Type("appointments")
11+
@JsonIgnoreProperties(ignoreUnknown = true)
12+
class Appointment @JsonCreator constructor(
13+
@Id(StringIdHandler::class) var id: String = "",
14+
@JsonProperty("animals") val animals: Boolean = false,
15+
@JsonProperty("end_time") val endTime: String = "",
16+
@JsonProperty("medical_dependency") val medicalDependency: Boolean = false,
17+
@JsonProperty("notes") val notes: String = "",
18+
@JsonProperty("on_ecr") val onEcr: Boolean = false,
19+
@JsonProperty("on_ecr_notes") val onEcrNotes: String = "",
20+
@JsonProperty("start_time") val startTime: String = ""
21+
) {
22+
constructor() : this(
23+
id = "",
24+
animals = false,
25+
endTime = "",
26+
medicalDependency = false,
27+
notes = "",
28+
onEcr = false,
29+
onEcrNotes = "",
30+
startTime = ""
31+
)
32+
}

src/main/kotlin/com/ctrlhub/core/projects/operations/OperationsRouter.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@ import com.ctrlhub.core.api.response.PaginatedList
55
import com.ctrlhub.core.projects.workorders.WorkOrdersRouter
66
import com.ctrlhub.core.projects.operations.response.Operation
77
import com.ctrlhub.core.iam.response.User
8+
import com.ctrlhub.core.projects.appointments.response.Appointment
89
import com.ctrlhub.core.projects.operations.templates.response.OperationTemplate
910
import com.ctrlhub.core.router.Router
1011
import com.ctrlhub.core.router.request.FilterOption
1112
import com.ctrlhub.core.router.request.JsonApiIncludes
12-
import com.ctrlhub.core.router.request.RequestParameters
1313
import com.ctrlhub.core.router.request.RequestParametersWithIncludes
1414
import io.ktor.client.HttpClient
1515

1616
enum class OperationIncludes(val value: String) : JsonApiIncludes {
1717
Template("template"),
18+
Appointments("appointment"),
19+
Properties("properties"),
1820
Forms("forms");
1921

2022
override fun value(): String {
@@ -46,7 +48,7 @@ class OperationsRouter(httpClient: HttpClient) : Router(httpClient) {
4648

4749
return fetchPaginatedJsonApiResources(
4850
endpoint, requestParameters.toMap(), Operation::class.java,
49-
OperationTemplate::class.java, User::class.java
51+
OperationTemplate::class.java, User::class.java, Appointment::class.java
5052
)
5153
}
5254

src/main/kotlin/com/ctrlhub/core/projects/operations/response/Operation.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.ctrlhub.core.projects.operations.response
22

33
import com.ctrlhub.core.api.Assignable
44
import com.ctrlhub.core.geo.Property
5+
import com.ctrlhub.core.projects.appointments.response.Appointment
56
import com.ctrlhub.core.projects.operations.templates.response.OperationTemplate
67
import com.ctrlhub.core.projects.response.Label
78
import com.fasterxml.jackson.annotation.JsonCreator
@@ -36,6 +37,9 @@ class Operation @JsonCreator constructor(
3637

3738
@Relationship("properties")
3839
var properties: java.util.List<Property>? = null,
40+
41+
@Relationship("appointment")
42+
var appointment: Appointment? = null
3943
) {
4044
constructor(): this(
4145
name = "",

src/test/kotlin/com/ctrlhub/core/projects/operations/OperationsRouterTest.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,44 @@ class OperationsRouterTest {
9797
assertEquals("Example Template Name", response.data[0].template?.name)
9898
}
9999
}
100+
101+
@Test
102+
fun `can retrieve all operations with included appointments`() {
103+
val jsonFilePath = Paths.get("src/test/resources/projects/operations/all-operations-with-included-appointments.json")
104+
val jsonContent = Files.readString(jsonFilePath)
105+
106+
val mockEngine = MockEngine { request ->
107+
respond(
108+
content = jsonContent,
109+
status = HttpStatusCode.OK,
110+
headers = headersOf(HttpHeaders.ContentType, "application/json")
111+
)
112+
}
113+
114+
val operationsRouter = OperationsRouter(httpClient = HttpClient(mockEngine).configureForTest())
115+
116+
runBlocking {
117+
val response = operationsRouter.all(
118+
organisationId = "123",
119+
requestParameters = OperationRequestParameters(
120+
includes = listOf(
121+
OperationIncludes.Appointments
122+
)
123+
)
124+
)
125+
126+
assertIs<PaginatedList<Operation>>(response)
127+
128+
// Find the operation that has an appointment
129+
val operationWithAppointment = response.data.find { it.appointment != null }
130+
assertNotNull(operationWithAppointment, "Should have at least one operation with an appointment")
131+
132+
// Validate the appointment is properly hydrated
133+
val appointment = operationWithAppointment?.appointment
134+
assertNotNull(appointment, "Appointment should not be null")
135+
assertEquals("appointment-1", appointment?.id)
136+
assertEquals("2025-08-15T07:00:00Z", appointment?.startTime)
137+
assertEquals("2025-08-15T11:00:00Z", appointment?.endTime)
138+
}
139+
}
100140
}

0 commit comments

Comments
 (0)