Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
abb5866
RWA-978 - Initial steps in pushing to MPI
mseaton Feb 21, 2025
bca50da
RWA-978 - Submit post data as json body
mseaton Feb 21, 2025
817ef7a
RWA-978 - Ready for initial testing
mseaton Feb 25, 2025
cbd4a9f
RWA-978 - Add additional checks
mseaton Feb 25, 2025
46379d4
RWA-978 - Rename from MPI to HIE
mseaton Feb 25, 2025
812a578
Fix typos
mseaton Feb 26, 2025
fe4002f
Expose more fine-grained messages and errors to front-end when connec…
mseaton Feb 26, 2025
43115f5
Merge branch 'RWA-978' of https://github.com/PIH/openmrs-module-rwand…
patieru12 Feb 27, 2025
6325154
Merge branch 'master' into RWA-978
mseaton Mar 4, 2025
3ca7e90
RWA-978 - Generate UPID using tempid; update attributes in HIE; updat…
mseaton Mar 4, 2025
be61ab0
Merge branch 'RWA-978' of https://github.com/PIH/openmrs-module-rwand…
patieru12 Mar 5, 2025
99f0b65
enable shr records to view on the clinician side
patieru12 Mar 27, 2025
ae1c51c
README.md
patieru12 Mar 27, 2025
586d22d
resolve conflict used to reduce the log size
patieru12 Apr 14, 2025
a6f623a
RWA-1010 - Add inpatient clinical forms to ward view for Rwanda
mseaton Apr 18, 2025
3f87c50
change fragment view to summarize visit in location first and later e…
patieru12 Apr 24, 2025
a23fd6f
Changed Admission type from IPD to OPD
nic10ben Apr 28, 2025
cfcc41e
RWA-1007 - Move drug administration date into a rowgroup header (#16)
mseaton May 1, 2025
4540afb
Do not allow editing insurance type
mseaton May 5, 2025
9ff2d98
RWA-1010 - Support custom forms endpoint based on extensions (#15)
mseaton May 6, 2025
68faf3b
RWA-1020 - Generate HL7 messages for radiology orders for integration…
mseaton May 19, 2025
ad77127
Remove incorrect comment
mseaton May 20, 2025
e62eff5
RWA-1019 - Use Primary Care ID as patient identifier
mseaton May 21, 2025
7062819
UHM-8650 - Ensure clinical forms in O3 are valid for given visit context
mseaton May 22, 2025
45eed79
Add return url to drug orders portlet
mseaton May 28, 2025
218e70b
Add context path to return url
mseaton May 28, 2025
7b29a7a
Add context path to header icon
mseaton May 29, 2025
25349fd
Normalize the patient identifier sent for PACS by removing "-" charac…
mseaton Jun 9, 2025
2c0c6dd
RWA-1025 - Add ability to update patient demographics in PACS (#18)
mseaton Jun 9, 2025
ca694cc
Fix naming convention
mseaton Jun 9, 2025
0667704
complete push encounter and Obs to SHR
patieru12 Jul 9, 2025
67218ff
RWA-1024 - Add ability to receive an HL7 radiology report update (ORU…
mseaton Jul 10, 2025
8e6dfc3
RWA-1023 - Provide a means to send / re-send an ORM message to PACS s…
mseaton Jul 11, 2025
d433c13
Ignore validation on all pipe parsing to avoid validation errors abou…
mseaton Jul 11, 2025
1b49c49
Remove sending phone numbers due to validation issues on the MockPacs…
mseaton Jul 11, 2025
387f825
Improved error handling on radiology order sending to PACS
mseaton Jul 28, 2025
d92eb2c
Remove encoded characters from reportText
mseaton Jul 29, 2025
7b13641
Controlling encounterDate in future
nic10ben Jul 29, 2025
6d603aa
Merge branch 'master' of https://github.com/PIH/openmrs-module-rwandaemr
nic10ben Jul 29, 2025
35feb63
RWA-1035 - Insurance eligibility checking
mseaton Aug 12, 2025
1eb3e8d
RWA-1035 - Insurance eligibility checking
mseaton Aug 12, 2025
219f34f
RWA-1035 - Insurance eligibility checking
mseaton Aug 12, 2025
c0cfb0b
RWA-1035 - Add dialog for choosing eligible member
mseaton Aug 14, 2025
9bc966d
Resolve conflict
patieru12 Aug 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
openmrs-module-rwandaemr
===================================
## openmrs-module-rwandaemr

The module hold all source code from imbemr module
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,31 @@
*/
package org.openmrs.module.rwandaemr;

import lombok.Getter;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.EncounterType;
import org.openmrs.Location;
import org.openmrs.LocationAttributeType;
import org.openmrs.PatientIdentifierType;
import org.openmrs.PersonAttributeType;
import org.openmrs.Provider;
import org.openmrs.api.EncounterService;
import org.openmrs.api.LocationService;
import org.openmrs.api.PatientService;
import org.openmrs.api.PersonService;
import org.openmrs.api.ProviderService;
import org.openmrs.module.initializer.api.InitializerService;
import org.openmrs.module.rwandaemr.radiology.RadiologyConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
* Config used by the Rwanda EMR module
*/
@Component
@Getter
public class RwandaEmrConfig {

protected Log log = LogFactory.getLog(getClass());
Expand All @@ -36,18 +42,25 @@ public class RwandaEmrConfig {
private final PatientService patientService;
private final LocationService locationService;
private final EncounterService encounterService;
private final ProviderService providerService;
private final InitializerService initializerService;
private final RadiologyConfig radiologyConfig;

public RwandaEmrConfig(@Autowired PatientService patientService,
public RwandaEmrConfig(
@Autowired PatientService patientService,
@Autowired PersonService personService,
@Autowired LocationService locationService,
@Autowired EncounterService encounterService,
@Autowired InitializerService initializerService) {
@Autowired ProviderService providerService,
@Autowired InitializerService initializerService,
@Autowired RadiologyConfig radiologyConfig) {
this.patientService = patientService;
this.personService = personService;
this.locationService = locationService;
this.encounterService = encounterService;
this.providerService = providerService;
this.initializerService = initializerService;
this.radiologyConfig = radiologyConfig;
}

public PatientIdentifierType getPrimaryCareIdentifierType() {
Expand Down Expand Up @@ -106,6 +119,18 @@ public LocationAttributeType getFosaId() {
return getLocationAttributeTypeByJsonKey("locationAttribute.fosaId.uuid");
}

public Location getUnknownLocation() {
return locationService.getLocation("Unknown location");
}

public Provider getUnknownProvider() {
return providerService.getUnknownProvider();
}

public Provider getProviderByIdentifier(String identifier) {
return providerService.getProviderByIdentifier(identifier);
}

public PatientIdentifierType getPatientIdentifierTypeByJsonKey(String jsonKey) {
String uuid = initializerService.getValueFromKey(jsonKey);
return getPatientIdentifierTypeByUuid(uuid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
*/
package org.openmrs.module.rwandaemr;

import org.openmrs.Encounter;
import org.openmrs.Location;
import org.openmrs.Obs;
import org.openmrs.Order;
import org.openmrs.Patient;
import org.openmrs.api.OpenmrsService;

Expand All @@ -26,6 +29,10 @@
@Transactional
public interface RwandaEmrService extends OpenmrsService {

List<Obs> getObsByOrder(Order order);

void saveEncounters(List<Encounter> encounters);

List<String> triggerSyncForPatient(Patient patient);

void updateVisitAndLoginLocations(List<Location> visitLocations, List<Location> loginLocations);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package org.openmrs.module.rwandaemr;

import lombok.Setter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Encounter;
Expand All @@ -31,15 +32,17 @@
import org.openmrs.Relationship;
import org.openmrs.Visit;
import org.openmrs.annotation.Authorized;
import org.openmrs.api.EncounterService;
import org.openmrs.api.LocationService;
import org.openmrs.api.context.Context;
import org.openmrs.api.db.hibernate.DbSessionFactory;
import org.openmrs.api.db.hibernate.ImmutableOrderInterceptor;
import org.openmrs.api.impl.BaseOpenmrsService;
import org.openmrs.module.emrapi.EmrApiConstants;
import org.openmrs.util.PrivilegeConstants;
import org.openmrs.validator.ValidateUtil;
import org.springframework.transaction.annotation.Transactional;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
Expand All @@ -53,6 +56,28 @@ public class RwandaEmrServiceImpl extends BaseOpenmrsService implements RwandaEm

protected Log log = LogFactory.getLog(getClass());

@Setter
private DbSessionFactory sessionFactory;

@Setter
private EncounterService encounterService;

@Transactional(readOnly = true)
@Authorized(PrivilegeConstants.GET_OBS)
@SuppressWarnings("unchecked")
public List<Obs> getObsByOrder(Order order) {
String query = "select o from Obs o where o.order = :order and o.voided = false";
return sessionFactory.getCurrentSession().createQuery(query).setParameter("order", order).list();
}

@Transactional
@Authorized(PrivilegeConstants.ADD_ENCOUNTERS)
public void saveEncounters(List<Encounter> encounters) {
for (Encounter encounter : encounters) {
encounterService.saveEncounter(encounter);
}
}

@Transactional
@Authorized(PrivilegeConstants.EDIT_PATIENTS)
public List<String> triggerSyncForPatient(Patient patient) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public static void configureAuthenticationSchemes() {
whitelist.add("/authenticationui/login/login.page");
whitelist.add("/appui/session/getLoginLocations.action");
whitelist.add("/csrfguard");
whitelist.add("/spa/**/*");
whitelist.add("*.js");
whitelist.add("*.css");
whitelist.add("*.gif");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package org.openmrs.module.rwandaemr.config;

import org.openmrs.Encounter;
import org.openmrs.Obs;
import org.openmrs.Patient;
import org.openmrs.api.context.Context;
import org.openmrs.event.Event;
import org.openmrs.event.EventListener;
import org.openmrs.module.rwandaemr.event.CreateInsurancePatientListener;
import org.openmrs.module.rwandaemr.event.HieEventListener;
import org.openmrs.module.rwandaemr.integration.UpdateClientRegistryPatientListener;
import org.openmrs.module.rwandaemr.integration.UpdateShrEncounterListener;
import org.openmrs.module.rwandaemr.integration.UpdateShrObsListener;
import org.openmrs.module.rwandaemr.radiology.RadiologyOrderEventListener;

/**
* Setup event listeners
Expand All @@ -16,20 +21,43 @@ public static void setup() {
Event.subscribe(Patient.class, Event.Action.CREATED.name(), getCreateInsurancePatientListener());
Event.subscribe(Patient.class, Event.Action.CREATED.name(), getUpdateClientRegistryPatientListener());
Event.subscribe(Patient.class, Event.Action.UPDATED.name(), getUpdateClientRegistryPatientListener());
/**
* Event for EMR to HIE encounter synchronization
*/
Event.subscribe(Encounter.class, Event.Action.CREATED.name(), getUpdateShrEncounterEventListener());
/**
* Event for EMR to HIE OBS synchronization
*/
Event.subscribe(Obs.class, Event.Action.CREATED.name(), getUpdateShrObservationEventListener());
getRadiologyOrderEventListener().setup();
}

public static void teardown() {
Event.unsubscribe(Patient.class, Event.Action.CREATED, getCreateInsurancePatientListener());
Event.unsubscribe(Patient.class, Event.Action.CREATED, getUpdateClientRegistryPatientListener());
Event.unsubscribe(Patient.class, Event.Action.UPDATED, getUpdateClientRegistryPatientListener());
Event.unsubscribe(Encounter.class, Event.Action.CREATED, getUpdateShrEncounterEventListener());
Event.unsubscribe(Obs.class, Event.Action.CREATED, getUpdateShrObservationEventListener());
getRadiologyOrderEventListener().teardown();
}

public static EventListener getCreateInsurancePatientListener() {
public static CreateInsurancePatientListener getCreateInsurancePatientListener() {
return Context.getRegisteredComponents(CreateInsurancePatientListener.class).get(0);
}

public static EventListener getUpdateClientRegistryPatientListener() {
public static UpdateClientRegistryPatientListener getUpdateClientRegistryPatientListener() {
return Context.getRegisteredComponents(UpdateClientRegistryPatientListener.class).get(0);
}

public static HieEventListener getUpdateShrEncounterEventListener(){
return Context.getRegisteredComponents(UpdateShrEncounterListener.class).get(0);
}

public static HieEventListener getUpdateShrObservationEventListener(){
return Context.getRegisteredComponents(UpdateShrObsListener.class).get(0);
}
public static RadiologyOrderEventListener getRadiologyOrderEventListener() {
return Context.getRegisteredComponents(RadiologyOrderEventListener.class).get(0);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void handlePatient(String patientUuid, MapMessage mapMessage) {
Admission admission = new Admission();
admission.setAdmissionDate(new Date());
admission.setInsurancePolicy(policy);
admission.setIsAdmitted(true);
admission.setIsAdmitted(false);
admission.setCreator(Context.getAuthenticatedUser());
admission.setCreatedDate(new Date());
admission.setDiseaseType("Default Disease Type");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.openmrs.module.rwandaemr.event;

import javax.jms.MapMessage;
import javax.jms.Message;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.api.context.Daemon;
import org.openmrs.event.EventListener;
import org.openmrs.module.DaemonToken;

import lombok.Setter;

public abstract class HieEventListener implements EventListener{
protected final Log log = LogFactory.getLog(getClass());
@Setter private static DaemonToken daemonToken;

@Override
public void onMessage(Message message){
try {
if(!(message instanceof MapMessage)){
throw new IllegalArgumentException("Message is not a MapMessage object");
}

MapMessage mapMessage = (MapMessage) message;
String uuid = mapMessage.getString("uuid");
if(StringUtils.isBlank(uuid)){
throw new IllegalArgumentException("Unable to retrieve encounter uuid from message: " + message);
}

Daemon.runInDaemonThread(() -> handle(uuid, mapMessage), daemonToken);
} catch(Exception e){
handleException(e);
}
}

public abstract void handle(String encounterUuid, MapMessage mapMessage);
public abstract void handleException(Exception e);
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public ClientRegistryPatient fetchPatientFromClientRegistry(String identifier, S
data = EntityUtils.toString(entity);
} catch (Exception ignored) {
}
log.debug("Data: " + data);
// log.debug("Data: " + data);
if (statusCode != 200) {
throw new IllegalStateException("Http Status Code: " + statusCode + "; Response: " + data);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs.module.rwandaemr.integration;

import lombok.Data;

/**
* Represents a generic response to hitting an integration endpoint
*/
@Data
public class IntegrationResponse {
private boolean enabled;
private boolean endpointAccessible;
private Integer responseCode;
private Object responseEntity;
private String errorMessage;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.openmrs.module.rwandaemr.integration;

import java.util.Date;
import javax.validation.constraints.NotNull;
import org.hl7.fhir.r4.model.Encounter;

import lombok.Data;

@Data
public class ShrEncounter {

private final Encounter encounter;

public ShrEncounter(@NotNull Encounter encounter){
this.encounter = encounter;
}

public String getEncounterUuid(){
if(encounter.hasId()){
return encounter.getIdBase();
}
return null;
}

public Encounter.EncounterLocationComponent getEncounterLocation(){
if(encounter.hasLocation()){
return encounter.getLocationFirstRep();
}
return null;
}

public String getEncounterTypeString(){
if(encounter.hasType()){
return encounter.getTypeFirstRep().getCodingFirstRep().getCode();
}
return null;
}

public String getEncounterTypeDisplay(){
if(encounter.hasType()){
return encounter.getTypeFirstRep().getCodingFirstRep().getDisplay();
}
return null;
}

public Encounter.EncounterParticipantComponent getEncounterSubject(){
if(encounter.hasSubject()){
return encounter.getParticipantFirstRep();
}
return null;
}

public Date getEncounterDate(){
if(encounter.hasPeriod()){
return encounter.getPeriod().getStart();
}
return null;
}
}
Loading