From c978be753e1be16d202fc0996322d115104bdde1 Mon Sep 17 00:00:00 2001 From: kavitha-sundararajan <90255023+kavitha-sundararajan@users.noreply.github.com> Date: Tue, 2 Jan 2024 01:38:53 +0530 Subject: [PATCH] Medication Administration Feature (#7) * [Ritesh] | 1. Repo set up. 2. Created Slot and Schedule entity 3.Saving IPD Medication Schedule without creating slots. * [Ritesh] | 1. Update package name 2. Added Dao and Service layer for reference 3. Minor fixes * [Ritesh] | 1.Rename Schedule Strategy to MedicationFrequency * [Ritesh] | 1. Migration for slot. 2. Slot creation from schedule * [Ritesh] | 1. Refactor SlotTimeCreationService * [Ritesh] | 1. Handle time zone issue while creating slots and schedule. * [Ritesh] | 1. Changing the url of saving medication * [Ritesh] | 1. Returning slots * [Ritesh] | Get schedule for Drug chart * [Ritesh] | Fix date time issue in slots response * [Ritesh] | Refactoring and Added test * [Ritesh] | 1. Change for reference id to subject reference id and by reference id to actor reference id. 2. Also added pre-condition before adding medication concept for ipd. * [Ritesh] | 1. Refactoring ServiceType * [Ritesh] | 1. Bug Fix return empty list if now slots are not present for a patient on specific day. * [Ritesh] | 1. Updated README file * [Ritesh] | 1. Fixed time zone issue in test * add. endpoint to get list of IPD medications scheduled for a patient * refactor. endpoint and updated tests in DAO and service classes * refactor. namings for schedule DAO methods * fix. test failures in ScheduleImpl * add. changes to create one schedule for a patient * update. columns in Schedule and Slot table * update. set end date as null * fix tests for Slot and Schedule Hiberate and DAOs. Updated responses for GET calls * fix tests Schedule DAO * remove unnecessary fields * API Change to accomodate Editable Remaining day slot start time for medication * Kavitha|Kalai Add Change for Medication Administration Save * Kavitha|Kalai - Medication Administration Create API Changes * Kavitha|Kalai - Medication Administration Create API Changes * Kavitha, Kalai | refactored patient reference param * Kavitha|Kalai - Medication Administration Create API Changes * Kavitha|Kalai - Medication Administration Create API Changes * Kavitha|Kalai - Medication Administration Create API Changes * Kavitha|Kalai - Medication Administration Create API Changes * Kavitha, Kalai | add medication administration reference in slot db and api * Kavitha|Kalai - Medication Administration Create API Changes * Kavitha, Kalai | added provider mapper and time converter * Kavitha | add adhoc and refactored scheduled medication administration * refactored schedule from medication administration request * Kavitha | refactored medication administration request and response * Kavitha | refactored annotation to medicationAdministrationNote * Kavitha | removed unused methods --------- Co-authored-by: Ritesh Ghiya Co-authored-by: Arjun-Go Co-authored-by: Kalaiyarasan Raja --- api/pom.xml | 22 ++++ .../module/ipd/api/dao/ScheduleDAO.java | 5 +- .../openmrs/module/ipd/api/dao/SlotDAO.java | 4 +- .../ipd/api/dao/impl/HibernateSlotDAO.java | 8 +- .../module/ipd/api/model/ServiceType.java | 4 +- .../openmrs/module/ipd/api/model/Slot.java | 7 ++ .../ipd/api/service/ScheduleService.java | 5 +- .../module/ipd/api/service/SlotService.java | 3 + .../api/service/impl/ScheduleServiceImpl.java | 4 - .../ipd/api/service/impl/SlotServiceImpl.java | 7 +- api/src/main/resources/liquibase.xml | 58 ++++++++++ omod/pom.xml | 18 +++ .../MedicationAdministrationNoteRequest.java | 26 +++++ .../MedicationAdministrationNoteResponse.java | 31 ++++++ ...icationAdministrationPerformerRequest.java | 21 ++++ ...cationAdministrationPerformerResponse.java | 28 +++++ .../MedicationAdministrationRequest.java | 39 +++++++ .../MedicationAdministrationResponse.java | 78 +++++++++++++ .../ipd/contract/MedicationSlotResponse.java | 4 + ...IPDMedicationAdministrationController.java | 71 ++++++++++++ .../MedicationAdministrationFactory.java | 81 ++++++++++++++ .../module/ipd/factory/SlotFactory.java | 24 ++-- .../IPDMedicationAdministrationService.java | 12 ++ ...PDMedicationAdministrationServiceImpl.java | 105 ++++++++++++++++++ .../service/impl/IPDScheduleServiceImpl.java | 4 +- omod/src/main/resources/config.xml | 2 +- pom.xml | 24 ++++ 27 files changed, 670 insertions(+), 25 deletions(-) create mode 100644 omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationNoteRequest.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationNoteResponse.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationPerformerRequest.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationPerformerResponse.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationRequest.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationResponse.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/controller/IPDMedicationAdministrationController.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/factory/MedicationAdministrationFactory.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/service/IPDMedicationAdministrationService.java create mode 100644 omod/src/main/java/org/openmrs/module/ipd/service/impl/IPDMedicationAdministrationServiceImpl.java diff --git a/api/pom.xml b/api/pom.xml index b28f5db..7dfdbee 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -104,14 +104,17 @@ org.openmrs.api openmrs-api + provided org.projectlombok lombok + provided org.openmrs.web openmrs-web + provided org.openmrs.module @@ -125,6 +128,25 @@ provided + + org.openmrs.module + fhir2-api + provided + + + + org.openmrs.module + fhir2-omod + provided + + + + org.bahmni.module + medication-administration-api + provided + + + org.openmrs.module webservices.rest-omod-common diff --git a/api/src/main/java/org/openmrs/module/ipd/api/dao/ScheduleDAO.java b/api/src/main/java/org/openmrs/module/ipd/api/dao/ScheduleDAO.java index 196a23b..7d85035 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/dao/ScheduleDAO.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/dao/ScheduleDAO.java @@ -4,16 +4,13 @@ import org.openmrs.module.ipd.api.model.Schedule; import org.openmrs.api.db.DAOException; import org.springframework.stereotype.Repository; -import org.openmrs.Concept; -import org.openmrs.module.ipd.api.model.Reference; -import java.util.List; @Repository public interface ScheduleDAO { Schedule getSchedule(Integer scheduleId) throws DAOException; - + Schedule saveSchedule(Schedule schedule) throws DAOException; Schedule getScheduleByVisit(Visit visit) throws DAOException; diff --git a/api/src/main/java/org/openmrs/module/ipd/api/dao/SlotDAO.java b/api/src/main/java/org/openmrs/module/ipd/api/dao/SlotDAO.java index df03ade..5896222 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/dao/SlotDAO.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/dao/SlotDAO.java @@ -13,7 +13,9 @@ public interface SlotDAO { Slot getSlot(Integer slotId) throws DAOException; - + + Slot getSlotByUUID(String uuid) throws DAOException; + Slot saveSlot(Slot slot) throws DAOException; List getSlotsBySubjectReferenceIdAndForDateAndServiceType(Reference subject, LocalDate forDate, Concept serviceType); diff --git a/api/src/main/java/org/openmrs/module/ipd/api/dao/impl/HibernateSlotDAO.java b/api/src/main/java/org/openmrs/module/ipd/api/dao/impl/HibernateSlotDAO.java index d58259b..59ecb5a 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/dao/impl/HibernateSlotDAO.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/dao/impl/HibernateSlotDAO.java @@ -31,7 +31,13 @@ public HibernateSlotDAO(SessionFactory sessionFactory) { public Slot getSlot(Integer slotId) throws DAOException { return sessionFactory.getCurrentSession().get(Slot.class, slotId); } - + + @Override + public Slot getSlotByUUID(String uuid) throws DAOException { + Slot s = (Slot)this.sessionFactory.getCurrentSession().createQuery("from Slot s where s.uuid = :uuid").setString("uuid", uuid).uniqueResult(); + return s; + } + @Override public Slot saveSlot(Slot slot) throws DAOException { sessionFactory.getCurrentSession().saveOrUpdate(slot); diff --git a/api/src/main/java/org/openmrs/module/ipd/api/model/ServiceType.java b/api/src/main/java/org/openmrs/module/ipd/api/model/ServiceType.java index 48af776..651daeb 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/model/ServiceType.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/model/ServiceType.java @@ -1,7 +1,9 @@ package org.openmrs.module.ipd.api.model; public enum ServiceType { - MEDICATION_REQUEST("MedicationRequest"); + MEDICATION_REQUEST("MedicationRequest"), + EMERGENCY_MEDICATION_REQUEST("EmergencyMedicationRequest"), + AS_NEEDED_MEDICATION_REQUEST("AsNeededMedicationRequest"); private final String conceptName; diff --git a/api/src/main/java/org/openmrs/module/ipd/api/model/Slot.java b/api/src/main/java/org/openmrs/module/ipd/api/model/Slot.java index 937de6b..33c6e7b 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/model/Slot.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/model/Slot.java @@ -79,6 +79,13 @@ public enum SlotStatus { @Column(name = "status", nullable = false) @Enumerated(EnumType.STRING) private SlotStatus status = SlotStatus.SCHEDULED; + + /** + * The reference of medication administration if the medication is administered + */ + @OneToOne + @JoinColumn(name = "medication_administration_id", referencedColumnName = "medication_administration_id") + private MedicationAdministration medicationAdministration; } diff --git a/api/src/main/java/org/openmrs/module/ipd/api/service/ScheduleService.java b/api/src/main/java/org/openmrs/module/ipd/api/service/ScheduleService.java index 3df1903..a370215 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/service/ScheduleService.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/service/ScheduleService.java @@ -1,21 +1,18 @@ package org.openmrs.module.ipd.api.service; -import org.openmrs.Concept; import org.openmrs.Visit; -import org.openmrs.module.ipd.api.model.Reference; import org.openmrs.module.ipd.api.model.Schedule; import org.openmrs.api.APIException; import org.openmrs.api.OpenmrsService; import org.springframework.stereotype.Service; -import java.util.List; @Service public interface ScheduleService extends OpenmrsService { // @Authorized({ PrivilegeConstants.EDIT_IPD_SCHEDULES }) Schedule getSchedule(Integer scheduleId) throws APIException; - + // @Authorized({ PrivilegeConstants.EDIT_IPD_SCHEDULES }) Schedule saveSchedule(Schedule schedule) throws APIException; diff --git a/api/src/main/java/org/openmrs/module/ipd/api/service/SlotService.java b/api/src/main/java/org/openmrs/module/ipd/api/service/SlotService.java index dc3fb56..468f6b1 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/service/SlotService.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/service/SlotService.java @@ -17,6 +17,9 @@ public interface SlotService extends OpenmrsService { // @Authorized({ PrivilegeConstants.EDIT_IPD_SLOTS }) Slot getSlot(Integer slotId) throws APIException; + // @Authorized({ PrivilegeConstants.EDIT_IPD_SLOTS }) + Slot getSlotByUUID(String uuid) throws APIException; + // @Authorized({ PrivilegeConstants.EDIT_IPD_SLOTS }) Slot saveSlot(Slot slot) throws APIException; diff --git a/api/src/main/java/org/openmrs/module/ipd/api/service/impl/ScheduleServiceImpl.java b/api/src/main/java/org/openmrs/module/ipd/api/service/impl/ScheduleServiceImpl.java index f331151..7521211 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/service/impl/ScheduleServiceImpl.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/service/impl/ScheduleServiceImpl.java @@ -1,9 +1,7 @@ package org.openmrs.module.ipd.api.service.impl; -import org.openmrs.Concept; import org.openmrs.Visit; import org.openmrs.module.ipd.api.dao.ScheduleDAO; -import org.openmrs.module.ipd.api.model.Reference; import org.openmrs.module.ipd.api.model.Schedule; import org.openmrs.module.ipd.api.service.ScheduleService; import org.openmrs.api.APIException; @@ -14,8 +12,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @Transactional public class ScheduleServiceImpl extends BaseOpenmrsService implements ScheduleService { diff --git a/api/src/main/java/org/openmrs/module/ipd/api/service/impl/SlotServiceImpl.java b/api/src/main/java/org/openmrs/module/ipd/api/service/impl/SlotServiceImpl.java index 25a33cd..318d39d 100644 --- a/api/src/main/java/org/openmrs/module/ipd/api/service/impl/SlotServiceImpl.java +++ b/api/src/main/java/org/openmrs/module/ipd/api/service/impl/SlotServiceImpl.java @@ -34,7 +34,12 @@ public SlotServiceImpl(SlotDAO slotDAO) { public Slot getSlot(Integer slotId) throws APIException { return slotDAO.getSlot(slotId); } - + + @Override + public Slot getSlotByUUID(String uuid) throws APIException { + return slotDAO.getSlotByUUID(uuid); + } + @Override public Slot saveSlot(Slot slot) throws APIException { return slotDAO.saveSlot(slot); diff --git a/api/src/main/resources/liquibase.xml b/api/src/main/resources/liquibase.xml index 1740908..8464105 100644 --- a/api/src/main/resources/liquibase.xml +++ b/api/src/main/resources/liquibase.xml @@ -218,4 +218,62 @@ ALTER TABLE ipd_schedule MODIFY COLUMN end_date datetime NULL; + + + + + + + + + + + + SELECT COUNT(*) FROM concept where short_name='EmergencyMedicationRequest' and description='EmergencyMedicationRequest'; + + + SELECT COUNT(*) FROM concept_name where name ='EmergencyMedicationRequest'; + + + Add concept for Emergency Medication Request + + insert into concept (retired, short_name, description, datatype_id, class_id, is_set, creator, date_created, + changed_by, date_changed, uuid) + values (0, 'EmergencyMedicationRequest', 'EmergencyMedicationRequest', + (select concept_datatype_id from concept_datatype where name = 'Text'), + (select concept_class_id from concept_class where name = 'Misc'), + 0, 1, now(), 1, now(), uuid()); + insert into concept_name (concept_id, name, locale, locale_preferred, creator, date_created, + concept_name_type, voided, uuid) + values ((select concept_id from concept where short_name='EmergencyMedicationRequest'), + 'EmergencyMedicationRequest', 'en', 1, 1, now(), 'FULLY_SPECIFIED', 0, uuid()); + + + + + + + SELECT COUNT(*) FROM concept where short_name='AsNeededMedicationRequest' and description='AsNeededMedicationRequest'; + + + SELECT COUNT(*) FROM concept_name where name ='AsNeededMedicationRequest'; + + + Add concept for As Needed Medication Request + + insert into concept (retired, short_name, description, datatype_id, class_id, is_set, creator, date_created, + changed_by, date_changed, uuid) + values (0, 'AsNeededMedicationRequest', 'AsNeededMedicationRequest', + (select concept_datatype_id from concept_datatype where name = 'Text'), + (select concept_class_id from concept_class where name = 'Misc'), + 0, 1, now(), 1, now(), uuid()); + insert into concept_name (concept_id, name, locale, locale_preferred, creator, date_created, + concept_name_type, voided, uuid) + values ((select concept_id from concept where short_name='AsNeededMedicationRequest'), + 'AsNeededMedicationRequest', 'en', 1, 1, now(), 'FULLY_SPECIFIED', 0, uuid()); + + + diff --git a/omod/pom.xml b/omod/pom.xml index ff83e3b..234d658 100644 --- a/omod/pom.xml +++ b/omod/pom.xml @@ -111,6 +111,24 @@ provided + + org.openmrs.module + fhir2-api + provided + + + + org.openmrs.module + fhir2-omod + provided + + + + org.bahmni.module + medication-administration-api + provided + + org.openmrs.test openmrs-test diff --git a/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationNoteRequest.java b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationNoteRequest.java new file mode 100644 index 0000000..87fdd58 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationNoteRequest.java @@ -0,0 +1,26 @@ +package org.openmrs.module.ipd.contract; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties +public class MedicationAdministrationNoteRequest { + private String uuid; + private String authorUuid; + private Long recordedTime; + private String text; + + public Date getRecordedTimeAsLocaltime() { + return this.recordedTime != null ? new Date(TimeUnit.SECONDS.toMillis(this.recordedTime)): new Date(); + } +} diff --git a/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationNoteResponse.java b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationNoteResponse.java new file mode 100644 index 0000000..b8e2f01 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationNoteResponse.java @@ -0,0 +1,31 @@ +package org.openmrs.module.ipd.contract; + +import lombok.*; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.openmrs.module.ipd.api.model.MedicationAdministrationNote; +import org.openmrs.module.webservices.rest.web.ConversionUtil; +import org.openmrs.module.webservices.rest.web.representation.Representation; + +import java.util.Date; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties +public class MedicationAdministrationNoteResponse { + private String uuid; + private Object author; + private Date recordedTime; + private String text; + + public static MedicationAdministrationNoteResponse createFrom(MedicationAdministrationNote openmrsObject) { + return MedicationAdministrationNoteResponse.builder() + .uuid(openmrsObject.getUuid()) + .author(ConversionUtil.convertToRepresentation(openmrsObject.getAuthor(), Representation.REF)) + .recordedTime(openmrsObject.getRecordedTime()) + .text(openmrsObject.getText()) + .build(); + } +} diff --git a/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationPerformerRequest.java b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationPerformerRequest.java new file mode 100644 index 0000000..c1d5a36 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationPerformerRequest.java @@ -0,0 +1,21 @@ +package org.openmrs.module.ipd.contract; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties +public class MedicationAdministrationPerformerRequest { + private String uuid; + private String providerUuid; + private String function; +} diff --git a/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationPerformerResponse.java b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationPerformerResponse.java new file mode 100644 index 0000000..3b1c1cf --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationPerformerResponse.java @@ -0,0 +1,28 @@ +package org.openmrs.module.ipd.contract; + +import lombok.*; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.openmrs.module.ipd.api.model.MedicationAdministrationPerformer; +import org.openmrs.module.webservices.rest.web.ConversionUtil; +import org.openmrs.module.webservices.rest.web.representation.Representation; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties +public class MedicationAdministrationPerformerResponse { + private String uuid; + private Object provider; + private String function; + + public static MedicationAdministrationPerformerResponse createFrom(MedicationAdministrationPerformer openmrsMedicationAdministrationPerformer) { + String function = openmrsMedicationAdministrationPerformer.getFunction() != null ? openmrsMedicationAdministrationPerformer.getFunction().getDisplayString() : null; + return MedicationAdministrationPerformerResponse.builder() + .uuid(openmrsMedicationAdministrationPerformer.getUuid()) + .provider(ConversionUtil.convertToRepresentation(openmrsMedicationAdministrationPerformer.getActor(), Representation.REF)) + .function(function) + .build(); + } +} diff --git a/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationRequest.java b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationRequest.java new file mode 100644 index 0000000..30270d6 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationRequest.java @@ -0,0 +1,39 @@ +package org.openmrs.module.ipd.contract; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MedicationAdministrationRequest { + + private String uuid; + private String patientUuid; + private String encounterUuid; + private String orderUuid; + private List providers; + private List notes; + private String status; + private String statusReason; + private String drugUuid; + private String dosingInstructions; + private Double dose; + private String doseUnitsUuid; + private String routeUuid; + private String siteUuid; + private Long administeredDateTime; + private String slotUuid; + + public Date getAdministeredDateTimeAsLocaltime() { + return this.administeredDateTime != null ? new Date(TimeUnit.SECONDS.toMillis(this.administeredDateTime)): null; + } + +} diff --git a/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationResponse.java b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationResponse.java new file mode 100644 index 0000000..4857b4e --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationAdministrationResponse.java @@ -0,0 +1,78 @@ +package org.openmrs.module.ipd.contract; + +import lombok.*; +import org.openmrs.api.context.Context; +import org.openmrs.module.ipd.api.model.MedicationAdministrationNote; +import org.openmrs.module.ipd.api.model.MedicationAdministrationPerformer; +import org.openmrs.module.webservices.rest.web.ConversionUtil; +import org.openmrs.module.webservices.rest.web.representation.Representation; + + +import java.util.Date; +import java.util.List; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MedicationAdministrationResponse { + + private String uuid; + private String patientUuid; + private String encounterUuid; + private String orderUuid; + private List providers; + private List notes; + private String status; + private String statusReason; + private Object drug; + private String dosingInstructions; + private Double dose; + private Object doseUnits; + private Object route; + private Object site; + private Date administeredDateTime; + + public static MedicationAdministrationResponse createFrom(org.openmrs.module.ipd.api.model.MedicationAdministration openmrsMedicationAdministration) { + if (openmrsMedicationAdministration == null) { + return null; + } + String status = openmrsMedicationAdministration.getStatus() != null ? openmrsMedicationAdministration.getStatus().getShortNameInLocale(Context.getLocale()).getName() : null; + String statusReason = openmrsMedicationAdministration.getStatusReason() != null ? openmrsMedicationAdministration.getStatusReason().getDisplayString() : null; + String patientUuid = openmrsMedicationAdministration.getPatient() != null ? openmrsMedicationAdministration.getPatient().getUuid() : null; + String encounterUuid = openmrsMedicationAdministration.getEncounter() != null ? openmrsMedicationAdministration.getEncounter().getUuid() : null; + String orderUuid = openmrsMedicationAdministration.getDrugOrder() != null ? openmrsMedicationAdministration.getDrugOrder().getUuid() : null; + + List providers = new java.util.ArrayList<>(); + if (openmrsMedicationAdministration.getPerformers() != null) { + for (MedicationAdministrationPerformer performer : openmrsMedicationAdministration.getPerformers()) { + providers.add(MedicationAdministrationPerformerResponse.createFrom(performer)); + } + } + List notes = new java.util.ArrayList<>(); + if (openmrsMedicationAdministration.getNotes() != null) { + for (MedicationAdministrationNote note : openmrsMedicationAdministration.getNotes()) { + notes.add(MedicationAdministrationNoteResponse.createFrom(note)); + } + } + return MedicationAdministrationResponse.builder() + .uuid(openmrsMedicationAdministration.getUuid()) + .administeredDateTime(openmrsMedicationAdministration.getAdministeredDateTime()) + .status(status) + .statusReason(statusReason) + .patientUuid(patientUuid) + .encounterUuid(encounterUuid) + .orderUuid(orderUuid) + .providers(providers) + .notes(notes) + .drug(ConversionUtil.convertToRepresentation(openmrsMedicationAdministration.getDrug(), Representation.REF)) + .dosingInstructions(openmrsMedicationAdministration.getDosingInstructions()) + .dose(openmrsMedicationAdministration.getDose()) + .doseUnits(ConversionUtil.convertToRepresentation(openmrsMedicationAdministration.getDoseUnits(), Representation.REF)) + .route(ConversionUtil.convertToRepresentation(openmrsMedicationAdministration.getRoute(), Representation.REF)) + .site(ConversionUtil.convertToRepresentation(openmrsMedicationAdministration.getSite(), Representation.REF)) + .build(); + } +} + diff --git a/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationSlotResponse.java b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationSlotResponse.java index 5e756bb..f2b4c97 100644 --- a/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationSlotResponse.java +++ b/omod/src/main/java/org/openmrs/module/ipd/contract/MedicationSlotResponse.java @@ -5,7 +5,9 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hl7.fhir.r4.model.MedicationAdministration; import org.openmrs.module.ipd.api.model.Slot; +import org.openmrs.module.ipd.factory.MedicationAdministrationFactory; import org.openmrs.module.webservices.rest.web.ConversionUtil; import org.openmrs.module.webservices.rest.web.representation.Representation; @@ -23,6 +25,7 @@ public class MedicationSlotResponse { private String status; private long startTime; private Object order; + private Object medicationAdministration; public static MedicationSlotResponse createFrom(Slot slot) { return MedicationSlotResponse.builder() @@ -32,6 +35,7 @@ public static MedicationSlotResponse createFrom(Slot slot) { .status(slot.getStatus().name()) .startTime(convertLocalDateTimeToUTCEpoc(slot.getStartDateTime())) .order(ConversionUtil.convertToRepresentation(slot.getOrder(), Representation.FULL)) + .medicationAdministration(MedicationAdministrationResponse.createFrom((slot.getMedicationAdministration()))) .build(); } } diff --git a/omod/src/main/java/org/openmrs/module/ipd/controller/IPDMedicationAdministrationController.java b/omod/src/main/java/org/openmrs/module/ipd/controller/IPDMedicationAdministrationController.java new file mode 100644 index 0000000..19843e6 --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ipd/controller/IPDMedicationAdministrationController.java @@ -0,0 +1,71 @@ +package org.openmrs.module.ipd.controller; + +import lombok.extern.slf4j.Slf4j; +import org.hl7.fhir.r4.model.MedicationAdministration; +import org.openmrs.module.fhir2.apiext.dao.FhirMedicationAdministrationDao; +import org.openmrs.module.ipd.api.service.SlotService; +import org.openmrs.module.ipd.contract.MedicationAdministrationRequest; +import org.openmrs.module.ipd.contract.MedicationAdministrationResponse; +import org.openmrs.module.ipd.factory.MedicationAdministrationFactory; +import org.openmrs.module.ipd.service.IPDMedicationAdministrationService; +import org.openmrs.module.webservices.rest.web.RestConstants; +import org.openmrs.module.webservices.rest.web.RestUtil; +import org.openmrs.module.webservices.rest.web.v1_0.controller.BaseRestController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.OK; + +@Controller +@RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/ipd") +@Slf4j +public class IPDMedicationAdministrationController extends BaseRestController { + + private final IPDMedicationAdministrationService ipdMedicationAdministrationService; + private final MedicationAdministrationFactory medicationAdministrationFactory; + + @Autowired + public IPDMedicationAdministrationController(IPDMedicationAdministrationService ipdMedicationAdministrationService, + SlotService slotService, + FhirMedicationAdministrationDao medicationAdministrationDao, + MedicationAdministrationFactory medicationAdministrationFactory) { + this.ipdMedicationAdministrationService = ipdMedicationAdministrationService; + this.medicationAdministrationFactory = medicationAdministrationFactory; + } + + @RequestMapping(value = "/scheduledMedicationAdministrations", method = RequestMethod.POST) + @ResponseBody + public ResponseEntity createScheduledMedicationAdministration(@RequestBody List medicationAdministrationRequestList) { + try { + List medicationAdministrationResponseList = new ArrayList<>(); + for (MedicationAdministrationRequest medicationAdministrationRequest : medicationAdministrationRequestList) { + MedicationAdministration medicationAdministration = ipdMedicationAdministrationService.saveScheduledMedicationAdministration(medicationAdministrationRequest); + medicationAdministrationResponseList.add(medicationAdministrationFactory.mapMedicationAdministrationToResponse(medicationAdministration)); + } + return new ResponseEntity<>(medicationAdministrationResponseList, OK); + } catch (Exception e) { + log.error("Runtime error while trying to create new medicationAdministration", e); + return new ResponseEntity<>(RestUtil.wrapErrorResponse(e, e.getMessage()), BAD_REQUEST); + } + } + + @RequestMapping(value = "/adhocMedicationAdministrations", method = RequestMethod.POST) + @ResponseBody + public ResponseEntity createAdhocMedicationAdministration(@RequestBody MedicationAdministrationRequest medicationAdministrationRequest) { + try { + MedicationAdministration medicationAdministration = ipdMedicationAdministrationService.saveAdhocMedicationAdministration(medicationAdministrationRequest); + MedicationAdministrationResponse medicationAdministrationResponse = medicationAdministrationFactory.mapMedicationAdministrationToResponse(medicationAdministration); + return new ResponseEntity<>(medicationAdministrationResponse, OK); + } catch (Exception e) { + log.error("Runtime error while trying to create new medicationAdministration", e); + return new ResponseEntity<>(RestUtil.wrapErrorResponse(e, e.getMessage()), BAD_REQUEST); + } + } + +} diff --git a/omod/src/main/java/org/openmrs/module/ipd/factory/MedicationAdministrationFactory.java b/omod/src/main/java/org/openmrs/module/ipd/factory/MedicationAdministrationFactory.java new file mode 100644 index 0000000..149581c --- /dev/null +++ b/omod/src/main/java/org/openmrs/module/ipd/factory/MedicationAdministrationFactory.java @@ -0,0 +1,81 @@ +package org.openmrs.module.ipd.factory; + +import org.openmrs.DrugOrder; +import org.openmrs.api.context.Context; +import org.openmrs.module.fhir2.apiext.translators.MedicationAdministrationStatusTranslator; +import org.openmrs.module.fhir2.apiext.translators.MedicationAdministrationTranslator; +import org.openmrs.module.ipd.api.model.MedicationAdministration; +import org.openmrs.module.ipd.api.model.MedicationAdministrationNote; +import org.openmrs.module.ipd.api.model.MedicationAdministrationPerformer; +import org.openmrs.module.ipd.contract.MedicationAdministrationNoteRequest; +import org.openmrs.module.ipd.contract.MedicationAdministrationPerformerRequest; +import org.openmrs.module.ipd.contract.MedicationAdministrationRequest; +import org.openmrs.module.ipd.contract.MedicationAdministrationResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + + +@Component +public class MedicationAdministrationFactory { + + private MedicationAdministrationTranslator medicationAdministrationTranslator; + private MedicationAdministrationStatusTranslator medicationAdministrationStatusTranslator; + + @Autowired + public MedicationAdministrationFactory(MedicationAdministrationTranslator medicationAdministrationTranslator, + MedicationAdministrationStatusTranslator medicationAdministrationStatusTranslator) { + this.medicationAdministrationTranslator = medicationAdministrationTranslator; + this.medicationAdministrationStatusTranslator = medicationAdministrationStatusTranslator; + } + + public MedicationAdministration mapRequestToMedicationAdministration(MedicationAdministrationRequest request, MedicationAdministration medicationAdministration) { + + medicationAdministration.setAdministeredDateTime(request.getAdministeredDateTimeAsLocaltime()); + medicationAdministration.setStatus(medicationAdministrationStatusTranslator.toOpenmrsType(org.hl7.fhir.r4.model.MedicationAdministration.MedicationAdministrationStatus.fromCode(request.getStatus()))); + medicationAdministration.setPatient(Context.getPatientService().getPatientByUuid(request.getPatientUuid())); + medicationAdministration.setEncounter(Context.getEncounterService().getEncounterByUuid(request.getEncounterUuid())); + medicationAdministration.setDrugOrder((DrugOrder) Context.getOrderService().getOrderByUuid(request.getOrderUuid())); + + List providers = new ArrayList<>(); + if (request.getProviders() != null) { + for (MedicationAdministrationPerformerRequest performer : request.getProviders()) { + MedicationAdministrationPerformer newProvider = new MedicationAdministrationPerformer(); + newProvider.setActor(Context.getProviderService().getProviderByUuid(performer.getProviderUuid())); + newProvider.setFunction(Context.getConceptService().getConceptByName(performer.getFunction())); + providers.add(newProvider); + } + } + medicationAdministration.setPerformers(new HashSet<>(providers)); + List notes = new ArrayList<>(); + if (request.getNotes() != null) { + for (MedicationAdministrationNoteRequest note : request.getNotes()) { + MedicationAdministrationNote newNote = new MedicationAdministrationNote(); + newNote.setAuthor(Context.getProviderService().getProviderByUuid(note.getAuthorUuid())); + newNote.setText(note.getText()); + newNote.setRecordedTime(note.getRecordedTimeAsLocaltime()); + notes.add(newNote); + } + } + medicationAdministration.setNotes(new HashSet<>(notes)); + medicationAdministration.setDrug(Context.getConceptService().getDrugByUuid(request.getDrugUuid())); + medicationAdministration.setDosingInstructions(request.getDosingInstructions()); + medicationAdministration.setDose(request.getDose()); + medicationAdministration.setDoseUnits(Context.getConceptService().getConceptByUuid(request.getDoseUnitsUuid())); + medicationAdministration.setRoute(Context.getConceptService().getConceptByUuid(request.getRouteUuid())); + medicationAdministration.setSite(Context.getConceptService().getConceptByUuid(request.getSiteUuid())); + + return medicationAdministration; + } + + public MedicationAdministrationResponse mapMedicationAdministrationToResponse(org.hl7.fhir.r4.model.MedicationAdministration fhirMedicationAdministration) { + MedicationAdministration openmrsMedicationAdministration = (MedicationAdministration) medicationAdministrationTranslator.toOpenmrsType(fhirMedicationAdministration); + MedicationAdministrationResponse response = MedicationAdministrationResponse.createFrom(openmrsMedicationAdministration); + return response; + } + + +} diff --git a/omod/src/main/java/org/openmrs/module/ipd/factory/SlotFactory.java b/omod/src/main/java/org/openmrs/module/ipd/factory/SlotFactory.java index 9373754..17c09e8 100644 --- a/omod/src/main/java/org/openmrs/module/ipd/factory/SlotFactory.java +++ b/omod/src/main/java/org/openmrs/module/ipd/factory/SlotFactory.java @@ -7,8 +7,11 @@ import org.openmrs.api.PatientService; import org.openmrs.module.bedmanagement.BedDetails; import org.openmrs.module.bedmanagement.service.BedManagementService; +import org.openmrs.module.ipd.api.model.MedicationAdministration; import org.openmrs.module.ipd.api.model.Schedule; +import org.openmrs.module.ipd.api.model.ServiceType; import org.openmrs.module.ipd.api.model.Slot; +import org.openmrs.module.ipd.api.service.SlotService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -16,24 +19,25 @@ import java.util.List; import java.util.stream.Collectors; -import static org.openmrs.module.ipd.api.model.ServiceType.MEDICATION_REQUEST; -import static org.openmrs.module.ipd.api.model.Slot.SlotStatus.SCHEDULED; - @Component public class SlotFactory { private final BedManagementService bedManagementService; private final ConceptService conceptService; private final PatientService patientService; + private final SlotService slotService; @Autowired - public SlotFactory(BedManagementService bedManagementService, ConceptService conceptService, PatientService patientService) { + public SlotFactory(BedManagementService bedManagementService, ConceptService conceptService, PatientService patientService,SlotService slotService) { this.bedManagementService = bedManagementService; this.conceptService = conceptService; this.patientService = patientService; + this.slotService = slotService; } - public List createSlotsForMedicationFrom(Schedule savedSchedule, List slotsStartTime, Order drugOrder) { + public List createSlotsForMedicationFrom(Schedule savedSchedule, List slotsStartTime, + Order drugOrder, MedicationAdministration medicationAdministration, + Slot.SlotStatus status, ServiceType serviceType) { return slotsStartTime.stream().map(slotStartTime -> { Slot slot = new Slot(); @@ -45,14 +49,20 @@ public List createSlotsForMedicationFrom(Schedule savedSchedule, List slotsStartTime = new ArrayList<>(); + slotsStartTime.add(DateTimeUtil.convertEpocUTCToLocalTimeZone(medicationAdministrationRequest.getAdministeredDateTime())); + ServiceType serviceType = openmrsMedicationAdministration.getDrugOrder() == null ? ServiceType.EMERGENCY_MEDICATION_REQUEST : ServiceType.AS_NEEDED_MEDICATION_REQUEST; + slotFactory.createSlotsForMedicationFrom(schedule, slotsStartTime, openmrsMedicationAdministration.getDrugOrder(), + openmrsMedicationAdministration, Slot.SlotStatus.COMPLETED, serviceType) + .forEach(slotService::saveSlot); + return medicationAdministration; + } + } + +} diff --git a/omod/src/main/java/org/openmrs/module/ipd/service/impl/IPDScheduleServiceImpl.java b/omod/src/main/java/org/openmrs/module/ipd/service/impl/IPDScheduleServiceImpl.java index e7ddbf3..707d46a 100644 --- a/omod/src/main/java/org/openmrs/module/ipd/service/impl/IPDScheduleServiceImpl.java +++ b/omod/src/main/java/org/openmrs/module/ipd/service/impl/IPDScheduleServiceImpl.java @@ -29,6 +29,8 @@ import java.util.List; import java.util.Optional; +import static org.openmrs.module.ipd.api.model.Slot.SlotStatus.SCHEDULED; + @Service @Transactional public class IPDScheduleServiceImpl implements IPDScheduleService { @@ -69,7 +71,7 @@ public Schedule saveMedicationSchedule(ScheduleMedicationRequest scheduleMedicat } DrugOrder order = (DrugOrder) orderService.getOrderByUuid(scheduleMedicationRequest.getOrderUuid()); List slotsStartTime = slotTimeCreationService.createSlotsStartTimeFrom(scheduleMedicationRequest, order); - slotFactory.createSlotsForMedicationFrom(savedSchedule, slotsStartTime, order) + slotFactory.createSlotsForMedicationFrom(savedSchedule, slotsStartTime, order, null, SCHEDULED, ServiceType.MEDICATION_REQUEST) .forEach(slotService::saveSlot); return savedSchedule; diff --git a/omod/src/main/resources/config.xml b/omod/src/main/resources/config.xml index 067eda0..7c18b69 100644 --- a/omod/src/main/resources/config.xml +++ b/omod/src/main/resources/config.xml @@ -13,8 +13,8 @@ org.openmrs.module.webservices.rest org.bahmni.module.bahmnicore org.openmrs.module.bedmanagement + org.bahmni.module.medication-administration - org.openmrs.module.ipd.api.IPDActivator diff --git a/pom.xml b/pom.xml index d5873b0..703f471 100644 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,7 @@ -Xmx1024m 0.7.9 1.18.26 + 1.11.0 @@ -163,6 +164,29 @@ provided + + + org.openmrs.module + fhir2-api + ${openmrsFhir2Version} + provided + + + + org.openmrs.module + fhir2-omod + ${openmrsFhir2Version} + provided + + + + org.bahmni.module + medication-administration-api + 1.0.0-SNAPSHOT + provided + + + org.openmrs.module