Bahmniapps customization and creating encounters and observations

I’m looking for possible feedback for a modification/extension to the bahmniapps module, and especially about how to create encounters and observations in a modification to bahmniapps module.

Here is some background for this: I am at a small non-profit TB hospital in the middle east. The hospital is working towards using a digital record keeping system for patient information. It is also very common for the hospital to collect X-Rays, especially chest X-Rays, for which we have a digital X-Ray modality and a recently set up PACS system using DCM4CHEE.

Looking at how bahmni could integrate with a PACS system, I decided to try something different than what bahmni had been set up to do. Decided to:

  1. have the EMR query the PACS system directly, to retrieve a list of studies for a patient each time a doctor looks at the patient dashboard.
  2. correspond studies from the PACS system with OpenMRS orders and with Radiology encounters and observations in OpenMRS

I also created a new ‘app’ in bahmni for the radiologist, in order for him to see todays x-rays, open x-rays in an external viewer, and add a Radiologist note to X-Rays. When adding a Radiologist note, an encounter is created using the following observation grouping:

  • External Radiology Observation
  • Radiologist Note (text value)
  • External Resource Uuid (stores uuid of external resource, and I’m thinking to set the date_created on this observation to match the creation date of external resource, if that is possible)

I’m working through how to create a new encounter + observations in the new radiology app. The simplest way is to mimic the way the clinical app makes POST calls to /openmrs/ws/rest/v1/bahmnicore/bahmniencounter. I was also looking at the items in openmrs-module-bahmniapps/ui/app/common/concept-set/, but I don’t understand those well and don’t know if they’d be useful.

I was wondering if anyone had thoughts or feedback about this, and also any advice on how to create encounters + observations?

Edit: I’ve tried a few ways to use the OpenMRS api directly, but I so far haven’t been able to make it work, via /openmrs/ws/rest/v1/encounter. Trying without adding a date_created to an observation, sending data:

{
  "patient": "8bcbd43d-e460-4bbf-9a74-a5642150af12",
  "encounterType": "81f57a25-3f10-11e4-adec-0800271c1b75",
  "location": "c1e42932-3f10-11e4-adec-0800271c1b75",
  "encounterProviders": ["c1c26908-3f10-11e4-adec-0800271c1b75"],
  "visit": "ea48f119-eb55-4449-913e-00c041db5a98",
  "obs": 
  [{
    "concept": "b3156f5a-fa54-442f-b157-ce1eb72b1679",
    "groupMembers": 
    [{
      "concept": "c3901c02-3f10-11e4-adec-0800271c1b75",
      "valueText": "Test"
    },{
      "concept": "2e62b98e-3264-4a67-9a9c-c16f7286c40d",
      "valueText": "1.2.840.113564.101010160.2017071811565087762"
    }]
  }]
}

I get a response:

{"error":{"message":"[null]","code":"org.openmrs.module.webservices.rest.web.v1_0.resource.openmrs1_9.EncounterResource1_9:79","detail":"java.lang.NullPointerException
	at org.openmrs.module.webservices.rest.web.v1_0.resource.openmrs1_9.EncounterResource1_9.save(EncounterResource1_9.java:79)
	at org.openmrs.module.webservices.rest.web.v1_0.resource.openmrs1_9.EncounterResource1_9.save(EncounterResource1_9.java:31)
	at org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource.create(DelegatingCrudResource.java:78)
	at org.openmrs.module.webservices.rest.web.v1_0.controller.MainResourceController.create(MainResourceController.java:92)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:177)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.openmrs.module.web.filter.ForcePasswordChangeFilter.doFilter(ForcePasswordChangeFilter.java:60)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:72)
	at org.openmrs.web.filter.GZIPFilter.doFilterInternal(GZIPFilter.java:64)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:70)
	at org.openmrs.module.webservices.rest.web.filter.AuthorizationFilter.doFilter(AuthorizationFilter.java:104)
	at org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:70)
	at org.springframework.web.filter.ShallowEtagHeaderFilter.doFilterInternal(ShallowEtagHeaderFilter.java:82)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.openmrs.module.web.filter.ModuleFilterChain.doFilter(ModuleFilterChain.java:70)
	at org.openmrs.module.web.filter.ModuleFilter.doFilter(ModuleFilter.java:54)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.openmrs.web.filter.OpenmrsFilter.doFilterInternal(OpenmrsFilter.java:108)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:150)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.openmrs.web.filter.StartupFilter.doFilter(StartupFilter.java:105)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:534)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1081)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
	at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Unknown Source)
"}}

It’s a different error when trying to set date_created on the last concept.

Hi @mdg583,

To help you troubleshooting, your NPE is thrown right here on ep.setEncounter(delegate):

for (EncounterProvider ep : delegate.getEncounterProviders()) {
  ep.setEncounter(delegate);
}

Meaning that the object ep is null, meaning that that something is not ok with the “encounter providers” of your encounter (none set basically).


Having said that, leveraging the already shipped Bahmni Apps services would certainly be the most appropriate way to keep the code base consistent. My two cents on this would be: try to reuse the Angular services already there in Bahmni Apps.

Here is an example of invoking encounterService.create(encounter) for example. I just looked quickly, but it seems likely that the create(encounter) method of encounterService is what you are looking for. Deep down it simply invokes REST WS’s EncounterResource1_9 btw. So wherever Bahmni Apps creates encounters, it must set the providers correctly otherwise it would bump right on the same problem as you did. You could sniff around and figure out the working POST data.

Thanks @mksd it is nice to get a broader perspective. I found what was wrong with my post requests, and I think for now I will create encounters this way, since it seemed somewhat more difficult to create observations using the services in the bahmni ui.

Here is what my post needed to look like, in particular I needed an encounterRole, and it was important to check that the defined concepts had the right data type:

{
  "patient": "5ab08279-071d-4113-beae-e45886578dfc",
  "encounterType": "81f57a25-3f10-11e4-adec-0800271c1b75",
  "location": "c1e42932-3f10-11e4-adec-0800271c1b75",
  "encounterProviders": [{
    "provider": "c1c26908-3f10-11e4-adec-0800271c1b75",
    "encounterRole": "a0b03050-c99b-11e0-9572-0800200c9a66"
  }],
  "visit": "c756981e-3221-45a6-944e-622af4f41477",
  "obs": [{
    "concept": "b3156f5a-fa54-442f-b157-ce1eb72b1679",
    "groupMembers": [{
      "concept": "c3901c02-3f10-11e4-adec-0800271c1b75",
      "value": "Test 2"
    }, {
      "concept": "2e62b98e-3264-4a67-9a9c-c16f7286c40d",
      "value": "1.2.4.0.13.1.4.2252867.20170719113626800.470.1"
    }]
  }]
}