Skip to content

Commit

Permalink
BAH-2962 | Added sms sending functionality . (#231)
Browse files Browse the repository at this point in the history
* Added SMS sending functionality on patient registration.
  • Loading branch information
anubhavBeehyv authored Oct 20, 2023
1 parent 536c8f9 commit ab8c5d1
Show file tree
Hide file tree
Showing 13 changed files with 361 additions and 9 deletions.
4 changes: 4 additions & 0 deletions bahmnicore-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@
<artifactId>joda-time</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.bahmni.module</groupId>
<artifactId>communication-api</artifactId>
</dependency>
<dependency>
<groupId>org.bahmni.module</groupId>
<artifactId>bahmni-emr-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.bahmni.module.bahmnicore.events;

import org.openmrs.api.context.Context;
import org.openmrs.api.context.UserContext;

import java.time.LocalDateTime;
import java.util.UUID;

public class BahmniEvent {

private static final long version = 1L;
public UserContext userContext;
public String eventId;
public BahmniEventType eventType;
public String payloadId;
public LocalDateTime publishedDateTime;

public BahmniEvent(BahmniEventType bahmniEventType) {
this.eventType = bahmniEventType;
this.eventId = UUID.randomUUID().toString();
this.publishedDateTime = LocalDateTime.now();
this.userContext= Context.getUserContext();
this.payloadId="";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.bahmni.module.bahmnicore.events;

public enum BahmniEventType {
BAHMNI_PATIENT_CREATED("bahmni-patient"),
BAHMNI_PATIENT_UPDATED("bahmni-patient"),
BAHMNI_ENCOUNTER_CREATED("bahmni-encounter"),
BAHMNI_ENCOUNTER_UPDATED("bahmni-encounter");

private final String topic;
BahmniEventType(String topic) {
this.topic = topic;
}
public String topic() {
return topic;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.bahmni.module.bahmnicore.events;

import org.openmrs.Encounter;

public class EncounterEvent extends BahmniEvent {

private Encounter encounter;

public EncounterEvent(BahmniEventType bahmniEventType, Encounter encounter) {
super(bahmniEventType);
this.encounter = encounter;
this.payloadId=encounter.getUuid();
}

public Encounter getEncounter() {
return encounter;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.bahmni.module.bahmnicore.events;

import org.openmrs.Patient;
import org.openmrs.api.context.Context;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.UUID;

public class PatientEvent extends BahmniEvent {

private Patient patient;

public PatientEvent(BahmniEventType bahmniEventType, Patient patient) {
super(bahmniEventType);
this.patient = patient;
this.payloadId=patient.getUuid();
}

public Patient getPatient() {
return patient;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.bahmni.module.bahmnicore.events.advice;

import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bahmni.module.bahmnicore.events.BahmniEventType;
import org.bahmni.module.bahmnicore.events.EncounterEvent;
import org.bahmni.module.bahmnicore.events.eventPublisher.BahmniEventPublisher;
import org.openmrs.Encounter;
import org.openmrs.api.context.Context;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.bahmni.module.bahmnicore.events.BahmniEventType.BAHMNI_ENCOUNTER_CREATED;
import static org.bahmni.module.bahmnicore.events.BahmniEventType.BAHMNI_ENCOUNTER_UPDATED;


public class EncounterAdvice implements AfterReturningAdvice, MethodBeforeAdvice {

private final Logger log = LogManager.getLogger(this.getClass());
private final BahmniEventPublisher eventPublisher;
private final ThreadLocal<Map<String, Integer>> threadLocal = new ThreadLocal<>();
private final String ENCOUNTER_ID_KEY = "encounterId";
private final Set<String> adviceMethodNames = Sets.newHashSet("saveEncounter");

public EncounterAdvice() {
this.eventPublisher = Context.getRegisteredComponent("bahmniEventPublisher", BahmniEventPublisher.class);
}

@Override
public void afterReturning(Object returnValue, Method method, Object[] arguments, Object target) {
if (adviceMethodNames.contains(method.getName())) {
Map<String, Integer> encounterInfo = threadLocal.get();
if (encounterInfo != null) {
BahmniEventType eventType = encounterInfo.get(ENCOUNTER_ID_KEY) == null ? BAHMNI_ENCOUNTER_CREATED : BAHMNI_ENCOUNTER_UPDATED;
threadLocal.remove();

Encounter encounter = (Encounter) returnValue;
EncounterEvent encounterEvent = new EncounterEvent(eventType, encounter);
eventPublisher.publishEvent(encounterEvent);

log.info("Successfully published event with uuid : " + encounter.getUuid());
}
}
}

@Override
public void before(Method method, Object[] objects, Object o) {
if (adviceMethodNames.contains(method.getName())) {
Encounter encounter = (Encounter) objects[0];
Map<String, Integer> encounterInfo = new HashMap<>(1);
encounterInfo.put(ENCOUNTER_ID_KEY, encounter.getId());
threadLocal.set(encounterInfo);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.bahmni.module.bahmnicore.events.advice;

import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bahmni.module.bahmnicore.events.BahmniEventType;
import org.bahmni.module.bahmnicore.events.PatientEvent;
import org.bahmni.module.bahmnicore.events.eventPublisher.BahmniEventPublisher;
import org.openmrs.Patient;
import org.openmrs.api.context.Context;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.bahmni.module.bahmnicore.events.BahmniEventType.BAHMNI_PATIENT_CREATED;
import static org.bahmni.module.bahmnicore.events.BahmniEventType.BAHMNI_PATIENT_UPDATED;


public class PatientAdvice implements AfterReturningAdvice, MethodBeforeAdvice {

private final Logger log = LogManager.getLogger(PatientAdvice.class);
private final BahmniEventPublisher eventPublisher;
private final ThreadLocal<Map<String,Integer>> threadLocal = new ThreadLocal<>();
private final String PATIENT_ID_KEY = "patientId";
private final Set<String> adviceMethodNames = Sets.newHashSet("savePatient");

public PatientAdvice() {
this.eventPublisher = Context.getRegisteredComponent("bahmniEventPublisher", BahmniEventPublisher.class);
}

@Override
public void afterReturning(Object returnValue, Method method, Object[] arguments, Object target) {
if (adviceMethodNames.contains(method.getName())) {
Map<String, Integer> patientInfo = threadLocal.get();
if (patientInfo != null) {
BahmniEventType eventType = patientInfo.get(PATIENT_ID_KEY) == null ? BAHMNI_PATIENT_CREATED : BAHMNI_PATIENT_UPDATED;
threadLocal.remove();

Patient patient = (Patient) returnValue;
PatientEvent patientEvent =new PatientEvent(eventType,patient);
eventPublisher.publishEvent(patientEvent);

log.info("Successfully published event with uuid : " + patient.getUuid());
}
}
}
@Override
public void before(Method method, Object[] objects, Object o) {
if (adviceMethodNames.contains(method.getName())) {
Patient patient = (Patient) objects[0];

Map<String, Integer> patientInfo = new HashMap<>(1);
patientInfo.put(PATIENT_ID_KEY, patient.getId());
threadLocal.set(patientInfo);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.bahmni.module.bahmnicore.events.eventListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bahmni.module.bahmnicore.events.BahmniEventType;
import org.bahmni.module.bahmnicore.events.PatientEvent;
import org.bahmni.module.communication.service.CommunicationService;
import org.bahmni.module.communication.service.MessageBuilderService;
import org.openmrs.Patient;
import org.openmrs.PersonAttribute;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.context.Context;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
public class PatientSmsEventListener {

private final Log log = LogFactory.getLog(this.getClass());


@Async("BahmniAsyncThreadExecutor")
@EventListener
public void onApplicationEvent(PatientEvent event) {
try {
Context.openSession();
Context.setUserContext(event.userContext);
if (event.eventType == BahmniEventType.BAHMNI_PATIENT_CREATED) {
handlePatientCreatedEvent(event.getPatient());
}
} catch(Exception e){
log.error("Exception occurred during event processing", e);
} finally{
Context.closeSession();
}
}

private void handlePatientCreatedEvent(Patient patient) {
AdministrationService administrationService = Context.getService(AdministrationService.class);
boolean patientRegistrationSMSProperty = Boolean.parseBoolean(administrationService.getGlobalProperty("sms.enableRegistrationSMSAlert","false"));
if (!patientRegistrationSMSProperty)
return;
String phoneNumber = getPhoneNumber(patient);
if (phoneNumber != null) {
MessageBuilderService messageBuilderService = Context.getRegisteredComponent("messageBuilderService", MessageBuilderService.class);
CommunicationService communicationService = Context.getRegisteredComponent("communicationService", CommunicationService.class);
String message=messageBuilderService.getRegistrationMessage(createArgumentsMapForPatientRegistration(patient));
communicationService.sendSMS(phoneNumber, message);
}
}

public Map<String, String> createArgumentsMapForPatientRegistration(Patient patient) {
String helpdeskNumber = Context.getAdministrationService().getGlobalPropertyObject("clinic.helpDeskNumber").getPropertyValue();
Map<String, String> arguments = new HashMap<>();
arguments.put("location", Context.getUserContext().getLocation().getName());
arguments.put("identifier", patient.getPatientIdentifier().getIdentifier());
arguments.put("patientname", patient.getGivenName() + " " + patient.getFamilyName());
arguments.put("gender", patient.getGender());
arguments.put("age", patient.getAge().toString());
arguments.put("helpdesknumber", helpdeskNumber);
return arguments;
}

private String getPhoneNumber(Patient patient) {
PersonAttribute phoneNumber = patient.getAttribute("phoneNumber");
if (phoneNumber == null) {
log.info("No mobile number found for the patient. SMS not sent.");
return null;
}
return phoneNumber.getValue();
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.bahmni.module.bahmnicore.events.eventPublisher;

import org.bahmni.module.bahmnicore.events.BahmniEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

@Component
public class BahmniEventPublisher implements ApplicationEventPublisherAware {

private ApplicationEventPublisher eventPublisher;

@Override
public void setApplicationEventPublisher(@NonNull ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
public void publishEvent(BahmniEvent event) {
this.eventPublisher.publishEvent(event);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* 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.bahmni.module.bahmnicore.util;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync
public class BahmniAsyncThreadExecutor {

@Bean(name = "BahmniAsyncThreadExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
return threadPoolTaskExecutor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.message.BasicStatusLine;
import org.bahmni.module.bahmnicore.web.v1_0.contract.BahmniMailContent;
import org.bahmni.module.communication.api.CommunicationService;
import org.bahmni.module.communication.model.MailContent;
import org.bahmni.module.communication.model.Recipient;
import org.bahmni.module.communication.service.CommunicationService;
import org.openmrs.Patient;
import org.openmrs.api.PatientService;
import org.openmrs.api.context.Context;
Expand All @@ -26,8 +25,8 @@
import org.springframework.web.bind.annotation.PathVariable;

@Controller
@RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/patient/{patientUuid}/send/")
public class TransmissionController extends BaseRestController {
@RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/patient/{patientUuid}/send/")//change to send-prescription-email
public class EmailCommunicationController extends BaseRestController {

private final Log log = LogFactory.getLog(this.getClass());

Expand Down Expand Up @@ -58,4 +57,4 @@ public Object sendEmail(@RequestBody BahmniMailContent bahmniMailContent, @PathV
return response;
}

}
}
Loading

0 comments on commit ab8c5d1

Please sign in to comment.