Skip to content

Commit af6b4d4

Browse files
feat: update controllers, DTOs, and mappers for patient and encounter modules
1 parent b5ec215 commit af6b4d4

8 files changed

Lines changed: 967 additions & 0 deletions

File tree

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
package com.countyhospital.healthapi.encounter.controller;
2+
3+
import com.countyhospital.healthapi.encounter.domain.Encounter;
4+
import com.countyhospital.healthapi.encounter.dto.request.EncounterRequest;
5+
import com.countyhospital.healthapi.encounter.dto.response.EncounterResponse;
6+
import com.countyhospital.healthapi.encounter.mapper.EncounterMapper;
7+
import com.countyhospital.healthapi.encounter.service.EncounterService;
8+
import com.countyhospital.healthapi.patient.domain.Patient;
9+
import com.countyhospital.healthapi.patient.service.PatientService;
10+
import io.swagger.v3.oas.annotations.Operation;
11+
import io.swagger.v3.oas.annotations.Parameter;
12+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
13+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
14+
import io.swagger.v3.oas.annotations.tags.Tag;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
import org.springframework.data.domain.Page;
18+
import org.springframework.data.domain.PageRequest;
19+
import org.springframework.data.domain.Pageable;
20+
import org.springframework.data.domain.Sort;
21+
import org.springframework.format.annotation.DateTimeFormat;
22+
import org.springframework.http.HttpStatus;
23+
import org.springframework.http.ResponseEntity;
24+
import org.springframework.web.bind.annotation.*;
25+
26+
import jakarta.validation.Valid;
27+
import java.time.LocalDateTime;
28+
import java.util.List;
29+
30+
@RestController
31+
@RequestMapping("/api/encounters")
32+
@Tag(name = "Encounter Management", description = "APIs for managing patient encounters")
33+
public class EncounterController {
34+
35+
private static final Logger logger = LoggerFactory.getLogger(EncounterController.class);
36+
37+
private final EncounterService encounterService;
38+
private final PatientService patientService;
39+
private final EncounterMapper encounterMapper;
40+
41+
public EncounterController(EncounterService encounterService, PatientService patientService,
42+
EncounterMapper encounterMapper) {
43+
this.encounterService = encounterService;
44+
this.patientService = patientService;
45+
this.encounterMapper = encounterMapper;
46+
}
47+
48+
@PostMapping
49+
@Operation(summary = "Create a new encounter", description = "Creates a new encounter for a patient")
50+
@ApiResponses({
51+
@ApiResponse(responseCode = "201", description = "Encounter created successfully"),
52+
@ApiResponse(responseCode = "400", description = "Invalid input data"),
53+
@ApiResponse(responseCode = "404", description = "Patient not found"),
54+
@ApiResponse(responseCode = "409", description = "Duplicate encounter")
55+
})
56+
public ResponseEntity<EncounterResponse> createEncounter(
57+
@Valid @RequestBody EncounterRequest encounterRequest) {
58+
logger.info("Received request to create encounter for patient ID: {}", encounterRequest.getPatientId());
59+
60+
Patient patient = patientService.getPatientById(encounterRequest.getPatientId());
61+
Encounter encounter = encounterMapper.toEntity(encounterRequest, patient);
62+
Encounter createdEncounter = encounterService.createEncounter(encounter);
63+
EncounterResponse response = encounterMapper.toResponse(createdEncounter);
64+
65+
logger.info("Successfully created encounter with ID: {}", createdEncounter.getId());
66+
return ResponseEntity.status(HttpStatus.CREATED).body(response);
67+
}
68+
69+
@GetMapping("/{id}")
70+
@Operation(summary = "Get encounter by ID", description = "Retrieves an encounter by its unique ID")
71+
@ApiResponses({
72+
@ApiResponse(responseCode = "200", description = "Encounter found"),
73+
@ApiResponse(responseCode = "404", description = "Encounter not found")
74+
})
75+
public ResponseEntity<EncounterResponse> getEncounterById(
76+
@Parameter(description = "Encounter ID") @PathVariable Long id) {
77+
logger.debug("Received request to get encounter by ID: {}", id);
78+
79+
Encounter encounter = encounterService.getEncounterById(id);
80+
EncounterResponse response = encounterMapper.toResponse(encounter);
81+
82+
return ResponseEntity.ok(response);
83+
}
84+
85+
@GetMapping("/patient/{patientId}")
86+
@Operation(summary = "Get encounters by patient ID", description = "Retrieves all encounters for a specific patient")
87+
@ApiResponses({
88+
@ApiResponse(responseCode = "200", description = "Encounters retrieved successfully"),
89+
@ApiResponse(responseCode = "404", description = "Patient not found")
90+
})
91+
public ResponseEntity<List<EncounterResponse>> getEncountersByPatientId(
92+
@Parameter(description = "Patient ID") @PathVariable Long patientId) {
93+
logger.debug("Received request to get encounters for patient ID: {}", patientId);
94+
95+
List<Encounter> encounters = encounterService.getEncountersByPatientId(patientId);
96+
List<EncounterResponse> response = encounterMapper.toResponseList(encounters);
97+
98+
return ResponseEntity.ok(response);
99+
}
100+
101+
@GetMapping("/patient/{patientId}/page")
102+
@Operation(summary = "Get encounters by patient ID with pagination",
103+
description = "Retrieves encounters for a specific patient with pagination support")
104+
@ApiResponses({
105+
@ApiResponse(responseCode = "200", description = "Encounters retrieved successfully"),
106+
@ApiResponse(responseCode = "404", description = "Patient not found")
107+
})
108+
public ResponseEntity<Page<EncounterResponse>> getEncountersByPatientId(
109+
@Parameter(description = "Patient ID") @PathVariable Long patientId,
110+
@Parameter(description = "Page number") @RequestParam(defaultValue = "0") int page,
111+
@Parameter(description = "Page size") @RequestParam(defaultValue = "10") int size,
112+
@Parameter(description = "Sort field") @RequestParam(defaultValue = "startDateTime") String sortBy,
113+
@Parameter(description = "Sort direction") @RequestParam(defaultValue = "desc") String direction) {
114+
115+
logger.debug("Received request to get encounters for patient ID: {} with pagination", patientId);
116+
117+
Sort sort = direction.equalsIgnoreCase("desc") ?
118+
Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
119+
Pageable pageable = PageRequest.of(page, size, sort);
120+
121+
Page<Encounter> encounters = encounterService.getEncountersByPatientId(patientId, pageable);
122+
Page<EncounterResponse> response = encounters.map(encounterMapper::toResponse);
123+
124+
return ResponseEntity.ok(response);
125+
}
126+
127+
@GetMapping
128+
@Operation(summary = "Get all encounters", description = "Retrieves all encounters with pagination support")
129+
@ApiResponses({
130+
@ApiResponse(responseCode = "200", description = "Encounters retrieved successfully")
131+
})
132+
public ResponseEntity<Page<EncounterResponse>> getAllEncounters(
133+
@RequestParam(defaultValue = "0") int page,
134+
@RequestParam(defaultValue = "20") int size,
135+
@RequestParam(defaultValue = "startDateTime") String sortBy,
136+
@RequestParam(defaultValue = "desc") String direction) {
137+
138+
logger.debug("Received request to get all encounters with pagination");
139+
140+
Sort sort = direction.equalsIgnoreCase("desc") ?
141+
Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
142+
Pageable pageable = PageRequest.of(page, size, sort);
143+
144+
Page<Encounter> encounters = encounterService.getAllEncounters(pageable);
145+
Page<EncounterResponse> response = encounters.map(encounterMapper::toResponse);
146+
147+
return ResponseEntity.ok(response);
148+
}
149+
150+
@GetMapping("/search/date-range")
151+
@Operation(summary = "Search encounters by date range", description = "Search encounters within a specific date range")
152+
@ApiResponses({
153+
@ApiResponse(responseCode = "200", description = "Search completed successfully"),
154+
@ApiResponse(responseCode = "400", description = "Invalid date range")
155+
})
156+
public ResponseEntity<List<EncounterResponse>> getEncountersByDateRange(
157+
@Parameter(description = "Start date time (yyyy-MM-dd HH:mm:ss)")
158+
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime start,
159+
160+
@Parameter(description = "End date time (yyyy-MM-dd HH:mm:ss)")
161+
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end) {
162+
163+
logger.debug("Received request to get encounters in date range: {} to {}", start, end);
164+
165+
List<Encounter> encounters = encounterService.getEncountersByDateRange(start, end);
166+
List<EncounterResponse> response = encounterMapper.toResponseList(encounters);
167+
168+
return ResponseEntity.ok(response);
169+
}
170+
171+
@GetMapping("/search/class/{encounterClass}")
172+
@Operation(summary = "Get encounters by class", description = "Retrieves encounters by encounter class")
173+
@ApiResponses({
174+
@ApiResponse(responseCode = "200", description = "Encounters retrieved successfully"),
175+
@ApiResponse(responseCode = "400", description = "Invalid encounter class")
176+
})
177+
public ResponseEntity<List<EncounterResponse>> getEncountersByClass(
178+
@Parameter(description = "Encounter class") @PathVariable String encounterClass) {
179+
180+
logger.debug("Received request to get encounters by class: {}", encounterClass);
181+
182+
List<Encounter> encounters = encounterService.getEncountersByClass(encounterClass);
183+
List<EncounterResponse> response = encounterMapper.toResponseList(encounters);
184+
185+
return ResponseEntity.ok(response);
186+
}
187+
188+
@PutMapping("/{id}")
189+
@Operation(summary = "Update encounter", description = "Updates an existing encounter")
190+
@ApiResponses({
191+
@ApiResponse(responseCode = "200", description = "Encounter updated successfully"),
192+
@ApiResponse(responseCode = "400", description = "Invalid input data"),
193+
@ApiResponse(responseCode = "404", description = "Encounter or patient not found"),
194+
@ApiResponse(responseCode = "409", description = "Duplicate encounter")
195+
})
196+
public ResponseEntity<EncounterResponse> updateEncounter(
197+
@Parameter(description = "Encounter ID") @PathVariable Long id,
198+
@Valid @RequestBody EncounterRequest encounterRequest) {
199+
200+
logger.info("Received request to update encounter with ID: {}", id);
201+
202+
Patient patient = patientService.getPatientById(encounterRequest.getPatientId());
203+
Encounter encounterDetails = encounterMapper.toEntity(encounterRequest, patient);
204+
Encounter updatedEncounter = encounterService.updateEncounter(id, encounterDetails);
205+
EncounterResponse response = encounterMapper.toResponse(updatedEncounter);
206+
207+
logger.info("Successfully updated encounter with ID: {}", id);
208+
return ResponseEntity.ok(response);
209+
}
210+
211+
@DeleteMapping("/{id}")
212+
@Operation(summary = "Delete encounter", description = "Deletes an encounter by ID")
213+
@ApiResponses({
214+
@ApiResponse(responseCode = "204", description = "Encounter deleted successfully"),
215+
@ApiResponse(responseCode = "404", description = "Encounter not found")
216+
})
217+
public ResponseEntity<Void> deleteEncounter(
218+
@Parameter(description = "Encounter ID") @PathVariable Long id) {
219+
220+
logger.info("Received request to delete encounter with ID: {}", id);
221+
222+
encounterService.deleteEncounter(id);
223+
224+
logger.info("Successfully deleted encounter with ID: {}", id);
225+
return ResponseEntity.noContent().build();
226+
}
227+
228+
@GetMapping("/patient/{patientId}/count")
229+
@Operation(summary = "Get encounter count by patient",
230+
description = "Returns the number of encounters for a specific patient")
231+
@ApiResponses({
232+
@ApiResponse(responseCode = "200", description = "Count retrieved successfully"),
233+
@ApiResponse(responseCode = "404", description = "Patient not found")
234+
})
235+
public ResponseEntity<Long> getEncounterCountByPatientId(
236+
@Parameter(description = "Patient ID") @PathVariable Long patientId) {
237+
238+
long count = encounterService.getEncounterCountByPatientId(patientId);
239+
return ResponseEntity.ok(count);
240+
}
241+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.countyhospital.healthapi.encounter.dto.request;
2+
3+
import java.time.LocalDateTime;
4+
5+
import com.fasterxml.jackson.annotation.JsonFormat;
6+
7+
import io.swagger.v3.oas.annotations.media.Schema;
8+
import jakarta.validation.constraints.NotBlank;
9+
import jakarta.validation.constraints.NotNull;
10+
import jakarta.validation.constraints.Pattern;
11+
import jakarta.validation.constraints.Size;
12+
13+
@Schema(description = "Request DTO for creating or updating an encounter")
14+
public class EncounterRequest {
15+
16+
@NotNull(message = "Patient ID is required")
17+
@Schema(description = "ID of the patient for this encounter", example = "1", required = true)
18+
private Long patientId;
19+
20+
@NotNull(message = "Start date time is required")
21+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
22+
@Schema(description = "Encounter start date time", example = "2024-01-15 09:30:00", required = true)
23+
private LocalDateTime startDateTime;
24+
25+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
26+
@Schema(description = "Encounter end date time", example = "2024-01-15 10:15:00")
27+
private LocalDateTime endDateTime;
28+
29+
@NotBlank(message = "Encounter class is required")
30+
@Pattern(regexp = "^(INPATIENT|OUTPATIENT|EMERGENCY|VIRTUAL)$",
31+
message = "Encounter class must be INPATIENT, OUTPATIENT, EMERGENCY, or VIRTUAL")
32+
@Schema(description = "Type of encounter", example = "OUTPATIENT", required = true,
33+
allowableValues = {"INPATIENT", "OUTPATIENT", "EMERGENCY", "VIRTUAL"})
34+
private String encounterClass;
35+
36+
@Size(max = 500, message = "Description must not exceed 500 characters")
37+
@Schema(description = "Encounter description or notes", example = "Routine checkup")
38+
private String description;
39+
40+
// Constructors
41+
public EncounterRequest() {}
42+
43+
public EncounterRequest(Long patientId, LocalDateTime startDateTime, LocalDateTime endDateTime,
44+
String encounterClass, String description) {
45+
this.patientId = patientId;
46+
this.startDateTime = startDateTime;
47+
this.endDateTime = endDateTime;
48+
this.encounterClass = encounterClass;
49+
this.description = description;
50+
}
51+
52+
// Getters and setters
53+
public Long getPatientId() { return patientId; }
54+
public void setPatientId(Long patientId) { this.patientId = patientId; }
55+
56+
public LocalDateTime getStartDateTime() { return startDateTime; }
57+
public void setStartDateTime(LocalDateTime startDateTime) { this.startDateTime = startDateTime; }
58+
59+
public LocalDateTime getEndDateTime() { return endDateTime; }
60+
public void setEndDateTime(LocalDateTime endDateTime) { this.endDateTime = endDateTime; }
61+
62+
public String getEncounterClass() { return encounterClass; }
63+
public void setEncounterClass(String encounterClass) { this.encounterClass = encounterClass; }
64+
65+
public String getDescription() { return description; }
66+
public void setDescription(String description) { this.description = description; }
67+
68+
@Override
69+
public String toString() {
70+
return "EncounterRequest{" +
71+
"patientId=" + patientId +
72+
", startDateTime=" + startDateTime +
73+
", endDateTime=" + endDateTime +
74+
", encounterClass='" + encounterClass + '\'' +
75+
", description='" + description + '\'' +
76+
'}';
77+
}
78+
}

0 commit comments

Comments
 (0)