Skip to content

Commit 39b8169

Browse files
authored
Merge pull request #19658 from hmislk/19657-three-tier-discharge-system
Implement three-tier discharge system: clinical, room, and hospital discharge
2 parents 962b84d + fd9a04d commit 39b8169

File tree

11 files changed

+845
-1
lines changed

11 files changed

+845
-1
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
* Open Hospital Management Information System
3+
*
4+
* Dr M H B Ariyaratne
5+
* Acting Consultant (Health Informatics)
6+
*/
7+
package com.divudi.bean.clinical;
8+
9+
import com.divudi.bean.common.SessionController;
10+
import com.divudi.core.util.JsfUtil;
11+
import com.divudi.core.data.SymanticType;
12+
import com.divudi.core.entity.clinical.ClinicalEntity;
13+
import com.divudi.core.facade.ClinicalEntityFacade;
14+
import java.io.Serializable;
15+
import java.util.ArrayList;
16+
import java.util.Date;
17+
import java.util.HashMap;
18+
import java.util.List;
19+
import java.util.Map;
20+
import javax.ejb.EJB;
21+
import javax.enterprise.context.SessionScoped;
22+
import javax.faces.component.UIComponent;
23+
import javax.faces.context.FacesContext;
24+
import javax.faces.convert.Converter;
25+
import javax.faces.convert.FacesConverter;
26+
import javax.inject.Inject;
27+
import javax.inject.Named;
28+
import javax.servlet.http.HttpServletResponse;
29+
import org.apache.poi.ss.usermodel.Row;
30+
import org.apache.poi.ss.usermodel.Sheet;
31+
import org.apache.poi.ss.usermodel.Workbook;
32+
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
33+
34+
/**
35+
* Manages configurable discharge condition values (e.g. Stable, DAMA, Referred)
36+
* used in the clinical discharge workflow.
37+
*
38+
* @author Dr. M. H. B. Ariyaratne
39+
*/
40+
@Named
41+
@SessionScoped
42+
public class DischargeConditionController implements Serializable {
43+
44+
private static final long serialVersionUID = 1L;
45+
46+
@Inject
47+
SessionController sessionController;
48+
49+
@EJB
50+
private ClinicalEntityFacade ejbFacade;
51+
52+
private ClinicalEntity current;
53+
private List<ClinicalEntity> items = null;
54+
private String selectText = "";
55+
56+
public DischargeConditionController() {
57+
}
58+
59+
public void prepareAdd() {
60+
current = new ClinicalEntity();
61+
current.setSymanticType(SymanticType.Discharge_Condition);
62+
}
63+
64+
public void saveSelected() {
65+
current.setSymanticType(SymanticType.Discharge_Condition);
66+
if (getCurrent().getId() != null && getCurrent().getId() > 0) {
67+
getFacade().edit(current);
68+
JsfUtil.addSuccessMessage("Updated");
69+
} else {
70+
current.setCreatedAt(new Date());
71+
current.setCreater(getSessionController().getLoggedUser());
72+
getFacade().create(current);
73+
JsfUtil.addSuccessMessage("Saved");
74+
}
75+
recreateModel();
76+
getItems();
77+
}
78+
79+
public void delete() {
80+
if (current != null) {
81+
current.setRetired(true);
82+
current.setRetiredAt(new Date());
83+
current.setRetirer(getSessionController().getLoggedUser());
84+
getFacade().edit(current);
85+
JsfUtil.addSuccessMessage("Deleted Successfully");
86+
} else {
87+
JsfUtil.addErrorMessage("Nothing to Delete");
88+
}
89+
recreateModel();
90+
getItems();
91+
current = null;
92+
getCurrent();
93+
}
94+
95+
public List<ClinicalEntity> getItems() {
96+
if (items == null) {
97+
Map m = new HashMap();
98+
m.put("t", SymanticType.Discharge_Condition);
99+
String sql = "select c from ClinicalEntity c where c.retired=false and c.symanticType=:t order by c.name";
100+
items = getFacade().findByJpql(sql, m);
101+
}
102+
return items;
103+
}
104+
105+
public List<ClinicalEntity> completeDischargeConditions(String qry) {
106+
if (qry == null || qry.trim().isEmpty()) {
107+
return new ArrayList<>();
108+
}
109+
List<ClinicalEntity> c;
110+
Map m = new HashMap();
111+
m.put("t", SymanticType.Discharge_Condition);
112+
m.put("n", "%" + qry.toUpperCase() + "%");
113+
String sql = "select c from ClinicalEntity c where c.retired=false and upper(c.name) like :n and c.symanticType=:t order by c.name";
114+
c = getFacade().findByJpql(sql, m, 10);
115+
if (c == null) {
116+
c = new ArrayList<>();
117+
}
118+
return c;
119+
}
120+
121+
public void downloadAsExcel() {
122+
getItems();
123+
FacesContext context = FacesContext.getCurrentInstance();
124+
try (Workbook workbook = new XSSFWorkbook()) {
125+
Sheet sheet = workbook.createSheet("Discharge Conditions");
126+
127+
Row headerRow = sheet.createRow(0);
128+
headerRow.createCell(0).setCellValue("No");
129+
headerRow.createCell(1).setCellValue("Name");
130+
headerRow.createCell(2).setCellValue("Code");
131+
headerRow.createCell(3).setCellValue("Description");
132+
133+
int rowNum = 1;
134+
for (ClinicalEntity item : items) {
135+
Row row = sheet.createRow(rowNum);
136+
row.createCell(0).setCellValue(rowNum);
137+
row.createCell(1).setCellValue(item.getName());
138+
row.createCell(2).setCellValue(item.getCode());
139+
row.createCell(3).setCellValue(item.getDescreption());
140+
rowNum++;
141+
}
142+
143+
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
144+
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
145+
response.setHeader("Content-Disposition", "attachment; filename=\"discharge_conditions.xlsx\"");
146+
147+
workbook.write(response.getOutputStream());
148+
context.responseComplete();
149+
} catch (Exception e) {
150+
JsfUtil.addErrorMessage("Error generating Excel file: " + e.getMessage());
151+
}
152+
}
153+
154+
private void recreateModel() {
155+
items = null;
156+
}
157+
158+
private ClinicalEntityFacade getFacade() {
159+
return ejbFacade;
160+
}
161+
162+
public ClinicalEntity getCurrent() {
163+
if (current == null) {
164+
current = new ClinicalEntity();
165+
}
166+
return current;
167+
}
168+
169+
public void setCurrent(ClinicalEntity current) {
170+
this.current = current;
171+
}
172+
173+
public String getSelectText() {
174+
return selectText;
175+
}
176+
177+
public void setSelectText(String selectText) {
178+
this.selectText = selectText;
179+
}
180+
181+
public SessionController getSessionController() {
182+
return sessionController;
183+
}
184+
185+
public void setSessionController(SessionController sessionController) {
186+
this.sessionController = sessionController;
187+
}
188+
189+
public ClinicalEntityFacade getEjbFacade() {
190+
return ejbFacade;
191+
}
192+
193+
public void setEjbFacade(ClinicalEntityFacade ejbFacade) {
194+
this.ejbFacade = ejbFacade;
195+
}
196+
197+
@FacesConverter("dischargeConditionConverter")
198+
public static class DischargeConditionConverter implements Converter {
199+
200+
@Override
201+
public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
202+
if (value == null || value.length() == 0) {
203+
return null;
204+
}
205+
try {
206+
DischargeConditionController controller = (DischargeConditionController) facesContext.getApplication()
207+
.getELResolver().getValue(facesContext.getELContext(), null, "dischargeConditionController");
208+
return controller.getEjbFacade().find(Long.valueOf(value));
209+
} catch (NumberFormatException e) {
210+
return null;
211+
}
212+
}
213+
214+
@Override
215+
public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
216+
if (object == null) {
217+
return null;
218+
}
219+
if (object instanceof ClinicalEntity) {
220+
ClinicalEntity o = (ClinicalEntity) object;
221+
return String.valueOf(o.getId());
222+
} else {
223+
throw new IllegalArgumentException("object " + object + " is of type "
224+
+ object.getClass().getName() + "; expected type: ClinicalEntity");
225+
}
226+
}
227+
}
228+
}

src/main/java/com/divudi/bean/inward/BhtSummeryController.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,10 @@ public void discharge() {
16201620
return;
16211621
}
16221622

1623+
if (!getPatientEncounter().isClinicallyDischarged()) {
1624+
JsfUtil.addErrorMessage("Warning: Clinical discharge has not been confirmed for this patient.");
1625+
}
1626+
16231627
getPatientEncounter().setDateOfDischarge(date);
16241628
getDischargeController().setCurrent((Admission) getPatientEncounter());
16251629
getDischargeController().discharge();

src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ public class InpatientClinicalDataController implements Serializable {
163163
private List<PatientEncounter> clinicalAssessments;
164164
private boolean viewOnly;
165165

166+
// Clinical discharge
167+
private PatientEncounter clinicalDischargeRecord;
168+
166169
@Inject
167170
private FavouriteController favouriteController;
168171

@@ -2228,6 +2231,90 @@ public String navigateToDischargeMedicinesFromAdmission(PatientEncounter admissi
22282231
return "/inward/inward_assessment_discharge_medicines?faces-redirect=true";
22292232
}
22302233

2234+
public String navigateToClinicalDischargeFromAdmission(PatientEncounter admission) {
2235+
this.parentAdmission = admission;
2236+
clinicalDischargeRecord = findOrCreateClinicalDischargeRecord(admission);
2237+
this.current = clinicalDischargeRecord;
2238+
fillCurrentPatientLists(admission.getPatient());
2239+
fillCurrentEncounterLists(clinicalDischargeRecord);
2240+
return "/inward/inward_clinical_discharge?faces-redirect=true";
2241+
}
2242+
2243+
private PatientEncounter findOrCreateClinicalDischargeRecord(PatientEncounter admission) {
2244+
Map<String, Object> m = new HashMap<>();
2245+
m.put("parent", admission);
2246+
m.put("type", PatientEncounterType.ClinicalDischarge);
2247+
m.put("ret", false);
2248+
String sql = "select e from PatientEncounter e "
2249+
+ "where e.parentEncounter=:parent "
2250+
+ "and e.patientEncounterType=:type "
2251+
+ "and e.retired=:ret "
2252+
+ "order by e.id desc";
2253+
List<PatientEncounter> existing = ejbFacade.findByJpql(sql, m, 1);
2254+
if (existing != null && !existing.isEmpty()) {
2255+
return existing.get(0);
2256+
}
2257+
PatientEncounter record = new PatientEncounter();
2258+
record.setParentEncounter(admission);
2259+
record.setPatient(admission.getPatient());
2260+
record.setPatientEncounterType(PatientEncounterType.ClinicalDischarge);
2261+
record.setEncounterDateTime(new Date());
2262+
record.setInstitution(sessionController.getInstitution());
2263+
record.setDepartment(sessionController.getDepartment());
2264+
return record;
2265+
}
2266+
2267+
public void saveClinicalDischarge() {
2268+
if (clinicalDischargeRecord == null) {
2269+
JsfUtil.addErrorMessage("No clinical discharge record found.");
2270+
return;
2271+
}
2272+
clinicalDischargeRecord.setDepartment(sessionController.getDepartment());
2273+
if (clinicalDischargeRecord.getId() != null) {
2274+
getFacade().edit(clinicalDischargeRecord);
2275+
JsfUtil.addSuccessMessage("Clinical discharge details saved.");
2276+
} else {
2277+
clinicalDischargeRecord.setCreatedAt(new Date());
2278+
clinicalDischargeRecord.setCreater(sessionController.getLoggedUser());
2279+
getFacade().create(clinicalDischargeRecord);
2280+
JsfUtil.addSuccessMessage("Clinical discharge record created.");
2281+
}
2282+
fillCurrentEncounterLists(clinicalDischargeRecord);
2283+
}
2284+
2285+
public void confirmClinicalDischarge() {
2286+
if (clinicalDischargeRecord == null) {
2287+
JsfUtil.addErrorMessage("No clinical discharge record found.");
2288+
return;
2289+
}
2290+
saveClinicalDischarge();
2291+
parentAdmission.setClinicallyDischarged(Boolean.TRUE);
2292+
parentAdmission.setClinicalDischargeDateTime(new Date());
2293+
parentAdmission.setClinicalDischargedBy(sessionController.getLoggedUser());
2294+
getFacade().edit(parentAdmission);
2295+
JsfUtil.addSuccessMessage("Clinical discharge confirmed.");
2296+
}
2297+
2298+
public void cancelClinicalDischarge() {
2299+
if (parentAdmission == null) {
2300+
JsfUtil.addErrorMessage("No admission found.");
2301+
return;
2302+
}
2303+
parentAdmission.setClinicallyDischarged(Boolean.FALSE);
2304+
parentAdmission.setClinicalDischargeDateTime(null);
2305+
parentAdmission.setClinicalDischargedBy(null);
2306+
getFacade().edit(parentAdmission);
2307+
JsfUtil.addSuccessMessage("Clinical discharge cancelled.");
2308+
}
2309+
2310+
public PatientEncounter getClinicalDischargeRecord() {
2311+
return clinicalDischargeRecord;
2312+
}
2313+
2314+
public void setClinicalDischargeRecord(PatientEncounter clinicalDischargeRecord) {
2315+
this.clinicalDischargeRecord = clinicalDischargeRecord;
2316+
}
2317+
22312318
public PatientEncounter getParentAdmission() {
22322319
return parentAdmission;
22332320
}

src/main/java/com/divudi/bean/inward/RoomChangeController.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.divudi.core.entity.inward.PatientRoom;
2121
import com.divudi.core.entity.inward.RoomFacilityCharge;
2222
import com.divudi.core.facade.AdmissionFacade;
23+
import com.divudi.core.facade.PatientEncounterFacade;
2324
import com.divudi.core.facade.PatientFacade;
2425
import com.divudi.core.facade.PatientRoomFacade;
2526
import com.divudi.core.facade.PersonFacade;
@@ -69,6 +70,8 @@ public class RoomChangeController implements Serializable {
6970
@EJB
7071
private AdmissionFacade ejbFacade;
7172
@EJB
73+
private PatientEncounterFacade patientEncounterFacade;
74+
@EJB
7275
private PersonFacade personFacade;
7376
@EJB
7477
private PatientFacade patientFacade;
@@ -303,6 +306,14 @@ public void discharge(PatientRoom pR) {
303306
pR.setDischargedBy(getSessionController().getLoggedUser());
304307
getPatientRoomFacade().edit(pR);
305308
notificationController.createNotification(pR, "Discharge");
309+
310+
// Sync room discharge to the parent encounter when this is the last (current) room
311+
if (pR.getNextRoom() == null && pR.getPatientEncounter() != null) {
312+
com.divudi.core.entity.PatientEncounter encounter = pR.getPatientEncounter();
313+
encounter.setRoomDischargeDateTime(pR.getDischargedAt());
314+
encounter.setRoomDischargedBy(getSessionController().getLoggedUser());
315+
patientEncounterFacade.edit(encounter);
316+
}
306317
}
307318

308319
public void dischargeWithCurrentTime(PatientRoom pR) {
@@ -330,6 +341,14 @@ public void dischargeWithCurrentTime(PatientRoom pR) {
330341
pR.setDischargedBy(getSessionController().getLoggedUser());
331342
getPatientRoomFacade().edit(pR);
332343
notificationController.createNotification(pR, "Discharge");
344+
345+
// Sync room discharge to the parent encounter when this is the last (current) room
346+
if (pR.getNextRoom() == null && pR.getPatientEncounter() != null) {
347+
com.divudi.core.entity.PatientEncounter encounter = pR.getPatientEncounter();
348+
encounter.setRoomDischargeDateTime(pR.getDischargedAt());
349+
encounter.setRoomDischargedBy(getSessionController().getLoggedUser());
350+
patientEncounterFacade.edit(encounter);
351+
}
333352
}
334353

335354
public void dischargeCancel(PatientRoom pR) {

0 commit comments

Comments
 (0)