diff --git a/server/src/main/java/org/hl7/davinci/endpoint/controllers/DataController.java b/server/src/main/java/org/hl7/davinci/endpoint/controllers/DataController.java index 0a1eabac6..509fee2a6 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/controllers/DataController.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/controllers/DataController.java @@ -44,8 +44,8 @@ public class DataController { @Autowired private ClientRepository clientRepository; - @Autowired - private RemsRepository remsRepository; + // @Autowired + // private RemsRepository remsRepository; @Autowired private YamlConfig myConfig; @@ -165,44 +165,4 @@ public RedirectView reload(@RequestParam String vsac_api_key) { return new RedirectView(newUrl); } - public void updateComplianceBundleStatus(String uid) { - try { - TimeUnit.SECONDS.sleep(30); - } - catch(Exception e) - { - System.out.println(e); - } - Rems rems = remsRepository.findById(uid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, uid + " not found")); - rems.setStatus("Approved"); - remsRepository.save(rems); - } - - public void updateComplianceBundleStatusInBackground (final String uid) { - Thread t = new Thread(() -> updateComplianceBundleStatus(uid)); - t.start(); - } - - @PostMapping(value = "/api/rems") - @CrossOrigin - public ResponseEntity postRems(@RequestBody String jsonData) { - JsonNode remsObject = JacksonUtil.toJsonNode(jsonData); - String id = UUID.randomUUID().toString().replace("-", ""); - - Rems complianceBundle = new Rems(); - complianceBundle.setCase_number(id); - complianceBundle.setComplianceBundle(remsObject); - complianceBundle.setStatus("Pending"); - remsRepository.save(complianceBundle); - updateComplianceBundleStatusInBackground(id); - return ResponseEntity.ok().body(complianceBundle); - - } - - @CrossOrigin - @GetMapping("/api/rems/{id}") - public ResponseEntity getRems(@PathVariable String id) { - Rems rems = remsRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, id + " not found")); - return ResponseEntity.ok().body(rems); - } } diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/DatabaseInit.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/DatabaseInit.java index 71e78fc9f..1cb358a68 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/rems/DatabaseInit.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/DatabaseInit.java @@ -46,22 +46,54 @@ CommandLineRunner initDatabase(DrugsRepository repository, RemsFhirRepository re return args -> { log.info("Preloading turalio"); Drug turalio = new Drug(); - - String questionnaire = readFile("src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/fhir/Questionnaire-R4-DrugHasREMS.json", Charset.defaultCharset()); - Requirement requirement = new Requirement(); - RemsFhir remsFhir = new RemsFhir(); - remsFhir.setResourceType(ResourceType.Questionnaire.toString()); - JsonNode questionnaireResource = JacksonUtil.toJsonNode(questionnaire); - remsFhir.setResource(questionnaireResource); - remsFhir.setId("q1"); - remsFhirRepository.save(remsFhir); - requirement.setRequirement(remsFhir); - requirement.setDescription("complete questionnaire"); - turalio.addRequirement(requirement); turalio.setId("turalio"); - repository.save(turalio); - requirement.setDrug(turalio); - requirementRepository.save(requirement); + turalio.setCodeSystem("http://www.nlm.nih.gov/research/umls/rxnorm"); + turalio.setCode("2183126"); + repository.save(turalio);; + + + // patient enrollment form requirement + String patientQuestionnaire = readFile("src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/fhir/Questionnaire-R4-DrugHasREMS.json", Charset.defaultCharset()); + Requirement patientEnrollmentRequirement = new Requirement(); + RemsFhir patientEnrollmentResource = new RemsFhir(); + patientEnrollmentResource.setResourceType(ResourceType.Questionnaire.toString()); + JsonNode patientQuestionnaireResource = JacksonUtil.toJsonNode(patientQuestionnaire); + patientEnrollmentResource.setResource(patientQuestionnaireResource); + patientEnrollmentResource.setId("turalio-patient-enrollment"); + remsFhirRepository.save(patientEnrollmentResource); + patientEnrollmentRequirement.setResource(patientEnrollmentResource); + patientEnrollmentRequirement.setDescription("complete patient enrollment questionnaire"); + patientEnrollmentRequirement.setDrug(turalio); + requirementRepository.save(patientEnrollmentRequirement); + + // prescriber enrollment form requirement + String prescriberQuestionnaire = readFile("src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/Questionnaire-R4-Prescriber-Enrollment.json", Charset.defaultCharset()); + Requirement prescriberEnrollmentRequirement = new Requirement(); + RemsFhir prescriberEnrollmentResource = new RemsFhir(); + prescriberEnrollmentResource.setResourceType(ResourceType.Questionnaire.toString()); + JsonNode prescriberQuestionnaireResource = JacksonUtil.toJsonNode(prescriberQuestionnaire); + prescriberEnrollmentResource.setResource(prescriberQuestionnaireResource); + prescriberEnrollmentResource.setId("turalio-prescriber-enrollment"); + remsFhirRepository.save(prescriberEnrollmentResource); + prescriberEnrollmentRequirement.setResource(prescriberEnrollmentResource); + prescriberEnrollmentRequirement.setDescription("complete prescriber enrollment questionnaire"); + prescriberEnrollmentRequirement.setDrug(turalio); + requirementRepository.save(prescriberEnrollmentRequirement); + + // prescriber knowledge assessment / certification sub-requirement + String prescriberKnowledgeQuestionnaire = readFile("src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/Questionnaire-R4-Prescriber-Knowledge-Assessment.json", Charset.defaultCharset()); + Requirement prescriberCertificationRequirement = new Requirement(); + RemsFhir prescriberKnowledgeResource = new RemsFhir(); + prescriberKnowledgeResource.setResourceType(ResourceType.Questionnaire.toString()); + JsonNode prescriberKnowledgeQuestionnaireResource = JacksonUtil.toJsonNode(prescriberKnowledgeQuestionnaire); + prescriberKnowledgeResource.setResource(prescriberKnowledgeQuestionnaireResource); + prescriberKnowledgeResource.setId("turalio-prescriber-knowledge-check"); + remsFhirRepository.save(prescriberKnowledgeResource); + prescriberCertificationRequirement.setResource(prescriberKnowledgeResource); + prescriberCertificationRequirement.setDescription("complete prescriber knowledge check"); + prescriberCertificationRequirement.setParent(prescriberEnrollmentRequirement); + requirementRepository.save(prescriberCertificationRequirement); + }; } } \ No newline at end of file diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/controller/RemsController.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/controller/RemsController.java index a9b9ae3d9..2564fba7f 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/rems/controller/RemsController.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/controller/RemsController.java @@ -1,9 +1,21 @@ package org.hl7.davinci.endpoint.rems.controller; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.fasterxml.jackson.databind.JsonNode; +import com.vladmihalcea.hibernate.type.json.internal.JacksonUtil; +import org.hl7.davinci.endpoint.rems.database.requirement.MetRequirement; +import org.hl7.davinci.endpoint.rems.database.requirement.MetRequirementRepository; +import org.hl7.davinci.endpoint.rems.database.requirement.Requirement; + import org.hl7.davinci.endpoint.Application; import org.hl7.davinci.endpoint.rems.database.drugs.Drug; import org.hl7.davinci.endpoint.rems.database.drugs.DrugsRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.hl7.davinci.endpoint.rems.database.rems.Rems; +import org.hl7.davinci.endpoint.rems.database.rems.RemsRepository; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; @@ -11,6 +23,19 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.http.ResponseEntity; +import org.springframework.web.servlet.view.RedirectView; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.http.HttpStatus; +import java.util.Arrays; + import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.logging.Logger; @@ -25,7 +50,13 @@ public class RemsController { @Autowired private DrugsRepository drugsRepository; - @GetMapping(value = "/rems/{id}") + @Autowired + private RemsRepository remsRepository; + + @Autowired + private MetRequirementRepository metRequirementsRepository; + + @GetMapping(value = "/drug/{id}") @CrossOrigin public ResponseEntity getRequirements(HttpServletRequest request, @PathVariable String id) throws IOException { Drug drug = drugsRepository.findById(id).get(); @@ -41,4 +72,87 @@ private ResponseEntity processRequirements(Drug drug) { .contentType(MediaType.parseMediaType(MediaType.APPLICATION_JSON_VALUE)) .body(drug); } + + public void updateRemsRequestStatus(String uid) { + try { + TimeUnit.SECONDS.sleep(30); + } + catch(Exception e) + { + System.out.println(e); + } + Rems rems = remsRepository.findById(uid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, uid + " not found")); + rems.setStatus("Approved"); + remsRepository.save(rems); + } + + public void updateRemsRequestStatusInBackground (final String uid) { + Thread t = new Thread(() -> updateRemsRequestStatus(uid)); + t.start(); + } + + @PostMapping(value = "/rems") + @CrossOrigin + public ResponseEntity postRems(@RequestBody String jsonData) { + JsonNode remsObject = JacksonUtil.toJsonNode(jsonData); + String id = UUID.randomUUID().toString().replace("-", ""); + + JsonNode params = getResource(remsObject, remsObject.get("entry").get(0).get("resource").get("focus").get("parameters").get("reference").textValue()); + + String prescriptionReference = ""; + for (JsonNode param : params.get("parameter")) { + if (param.get("name").textValue().equals("prescription")) { + prescriptionReference = param.get("reference").textValue(); + } + } + + JsonNode presciption = getResource(remsObject, prescriptionReference); + String prescriptionSystem = presciption.get("medicationCodeableConcept").get("coding").get(0).get("system").textValue(); + String prescriptionCode = presciption.get("medicationCodeableConcept").get("coding").get(0).get("code").textValue(); + Drug drug = drugsRepository.findDrugByCode(prescriptionSystem, prescriptionCode).get(0); + + + + Rems remsRequest = new Rems(); + remsRequest.setCase_number(id); + remsRequest.setStatus("Pending"); + remsRequest.setResource(remsObject); + remsRepository.save(remsRequest); + + // this loop needs to change to handle multiple levels of sub-requirement conditions + // this loop needs to also handle parsing out resources for each requirement - may need to be separate endpoints + for (Requirement requirement : drug.getRequirements()) { + MetRequirement metReq = new MetRequirement(); + metReq.setRequirement(requirement); + metReq.setRemsRequest(remsRequest); + remsRequest.addMetRequirement(metReq); + metRequirementsRepository.save(metReq); + } + remsRepository.save(remsRequest); + updateRemsRequestStatusInBackground(id); + return ResponseEntity.ok().body(remsRequest); + + } + + @CrossOrigin + @GetMapping("/rems/{id}") + public ResponseEntity getRems(@PathVariable String id) { + Rems rems = remsRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, id + " not found")); + return ResponseEntity.ok().body(rems); + } + + public JsonNode getResource(JsonNode bundle, String resourceReference) { + String[] temp = resourceReference.split("/"); + String _resourceType = temp[0]; + String _id = temp[1]; + + for (int i = 0; i < bundle.get("entry").size(); i++) { + if ((bundle.get("entry").get(i).get("resource").get("resourceType").textValue().equals(_resourceType)) + && (bundle.get("entry").get(i).get("resource").get("id").textValue().equals(_id))) { + return bundle.get("entry").get(i).get("resource"); + } + } + return null; + } + } \ No newline at end of file diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/drugs/Drug.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/drugs/Drug.java index b576f2aca..0ec47c097 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/drugs/Drug.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/drugs/Drug.java @@ -24,7 +24,7 @@ public class Drug { @Column(name = "createdAt", nullable = false) private String createdAt; - @OneToMany(mappedBy="drug") + @OneToMany(mappedBy="drug", fetch = FetchType.EAGER, cascade = CascadeType.ALL) private List requirements = new ArrayList<>(); public Drug() { diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/drugs/DrugsRepository.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/drugs/DrugsRepository.java index 324c8f33b..de10fa8d8 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/drugs/DrugsRepository.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/drugs/DrugsRepository.java @@ -5,6 +5,8 @@ import org.springframework.data.rest.core.annotation.RepositoryRestResource; import org.springframework.stereotype.Repository; import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.data.repository.query.Param; + import java.util.List; @@ -18,5 +20,7 @@ public interface DrugsRepository extends CrudRepository { "SELECT r FROM Drug r") List findLogs(); + @Query("SELECT r FROM Drug r where r.codeSystem = :system and r.code = :code") + List findDrugByCode(@Param("system") String system, @Param("code") String code); } diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/fhir/RemsFhir.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/fhir/RemsFhir.java index 945788f29..2c06e6062 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/fhir/RemsFhir.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/fhir/RemsFhir.java @@ -22,7 +22,7 @@ public class RemsFhir { private String createdAt; @Type(type = "json") - @Column(columnDefinition = "json", name = "complianceBundle", nullable = false, length = 10000000) + @Column(columnDefinition = "json", name = "resource", nullable = false, length = 10000000) private JsonNode resource; diff --git a/server/src/main/java/org/hl7/davinci/endpoint/database/Rems.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/Rems.java similarity index 50% rename from server/src/main/java/org/hl7/davinci/endpoint/database/Rems.java rename to server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/Rems.java index 60511251e..b59975ac6 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/database/Rems.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/Rems.java @@ -1,4 +1,9 @@ -package org.hl7.davinci.endpoint.database; +package org.hl7.davinci.endpoint.rems.database.rems; +import org.hl7.davinci.endpoint.rems.database.requirement.MetRequirement; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.*; + import javax.persistence.Column; import javax.persistence.Entity; @@ -18,13 +23,17 @@ public class Rems { @Column(name = "case_number", nullable = false, length = 100) private String case_number; - @Type(type = "json") - @Column(columnDefinition = "json", name = "complianceBundle", nullable = false, length = 10000000) - private JsonNode complianceBundle; @Column(name = "status", nullable = false, length = 100) private String status; + @Type(type = "json") + @Column(columnDefinition = "json", name = "resource", nullable = false, length = 10000000) + private JsonNode resource; + + @OneToMany(mappedBy="remsRequest", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + private List metRequirements = new ArrayList<>(); + public void Rems() {} public String getCase_number() { @@ -35,14 +44,6 @@ public void setCase_number(String id) { this.case_number = id; } - public JsonNode getComplianceBundle() { - return this.complianceBundle; - } - - public void setComplianceBundle(JsonNode jsonParam) { - this.complianceBundle = jsonParam; - } - public String getStatus() { return this.status; } @@ -50,4 +51,24 @@ public String getStatus() { public void setStatus(String statusParam) { this.status = statusParam; } + + public List getMetRequirements() { + return this.metRequirements; +} + +public void setMetRequirement(List metRequirements) { + this.metRequirements = metRequirements; +} + +public void addMetRequirement(MetRequirement metRequirement) { + this.metRequirements.add(metRequirement); +} + +public JsonNode getResource() { + return this.resource; +} + +public void setResource(JsonNode resource) { + this.resource = resource; +} } diff --git a/server/src/main/java/org/hl7/davinci/endpoint/database/RemsRepository.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsRepository.java similarity index 91% rename from server/src/main/java/org/hl7/davinci/endpoint/database/RemsRepository.java rename to server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsRepository.java index df21ac22e..2e641987b 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/database/RemsRepository.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsRepository.java @@ -1,4 +1,4 @@ -package org.hl7.davinci.endpoint.database; +package org.hl7.davinci.endpoint.rems.database.rems; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; diff --git a/server/src/main/java/org/hl7/davinci/endpoint/database/RemsService.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsService.java similarity index 77% rename from server/src/main/java/org/hl7/davinci/endpoint/database/RemsService.java rename to server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsService.java index ad2bb034d..04cc1a8bb 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/database/RemsService.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsService.java @@ -1,4 +1,4 @@ -package org.hl7.davinci.endpoint.database; +package org.hl7.davinci.endpoint.rems.database.rems; public interface RemsService { Iterable findAll(); diff --git a/server/src/main/java/org/hl7/davinci/endpoint/database/RemsServiceImpl.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsServiceImpl.java similarity index 92% rename from server/src/main/java/org/hl7/davinci/endpoint/database/RemsServiceImpl.java rename to server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsServiceImpl.java index b8070b859..dc4c06e06 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/database/RemsServiceImpl.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/rems/RemsServiceImpl.java @@ -1,4 +1,4 @@ -package org.hl7.davinci.endpoint.database; +package org.hl7.davinci.endpoint.rems.database.rems; import org.springframework.beans.factory.annotation.Autowired; diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/MetRequirement.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/MetRequirement.java new file mode 100644 index 000000000..56a64a356 --- /dev/null +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/MetRequirement.java @@ -0,0 +1,114 @@ +package org.hl7.davinci.endpoint.rems.database.requirement; +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.hl7.davinci.endpoint.rems.database.drugs.Drug; +import org.hl7.davinci.endpoint.rems.database.fhir.RemsFhir; +import org.hl7.davinci.endpoint.rems.database.rems.Rems; +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.*; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +@Entity +@Table(name = "metRequirement") +public class MetRequirement { + @Id + @GeneratedValue + @Column(name = "id", nullable = false) + private Integer id; + + @Column(name = "createdAt", nullable = false) + private String createdAt; + + @Column(name = "completed", nullable = false) + private boolean completed ; + + // FHIR resource which defines the requirement (task, questionnaire, etc) + @JoinColumn(name = "completedRequirement", nullable = true) + @OneToOne(fetch = FetchType.EAGER) + private RemsFhir completedRequirement; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="REQUIREMENT_ID") + @JsonIgnore + private Requirement requirement; + + @ManyToOne + @JoinColumn(name="REMS_REQUEST") + @JsonIgnore + private Rems remsRequest; + + @OneToMany(mappedBy="parentMetRequirement", fetch = FetchType.EAGER) + private List childMetRequirements = new ArrayList<>(); + + @ManyToOne + @JoinColumn(name="PARENT_MET_REQUIREMENT") + @JsonIgnore + private MetRequirement parentMetRequirement; + + public MetRequirement() { + this.createdAt = ZonedDateTime.now().format(DateTimeFormatter.ofPattern( "uuuu.MM.dd.HH.mm.ss" )); + this.completed = false; } + + public Rems getRemsRequest() { + return this.remsRequest; + } + + public void setRemsRequest(Rems request) { + this.remsRequest = request; + } + + public RemsFhir getCompletedRequirement() { + return this.completedRequirement; + } + + public void setCompletedRequirement(RemsFhir requirement) { + this.completedRequirement = requirement; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(boolean completed) { + this.completed = completed; + } + + public Requirement getRequirement() { + return requirement; + } + + public void setRequirement(Requirement requirement) { + this.requirement = requirement; + } + + public List getChildren() { + return this.childMetRequirements; + } + + public void setChildren(List requirements) { + this.childMetRequirements = requirements; + } + + public void addChild(MetRequirement requirement) { + this.childMetRequirements.add(requirement); + } + + public MetRequirement getParent() { + return this.parentMetRequirement; + } + + public void setParent(MetRequirement requirement) { + this.parentMetRequirement = requirement; + } + +} diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/MetRequirementRepository.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/MetRequirementRepository.java new file mode 100644 index 000000000..d375b937f --- /dev/null +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/MetRequirementRepository.java @@ -0,0 +1,23 @@ +package org.hl7.davinci.endpoint.rems.database.requirement; + +import java.util.List; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; +import org.springframework.stereotype.Repository; +import org.springframework.web.bind.annotation.CrossOrigin; + + +@RepositoryRestResource +@CrossOrigin(origins = "http://localhost:4200") +@Repository +public interface MetRequirementRepository extends CrudRepository { + + @Query( + "SELECT r FROM MetRequirement r") + List findAll(); + +} + + diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/Requirement.java b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/Requirement.java index d1db8fa98..f9efa8bf5 100644 --- a/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/Requirement.java +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/database/requirement/Requirement.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.hl7.davinci.endpoint.rems.database.drugs.Drug; import org.hl7.davinci.endpoint.rems.database.fhir.RemsFhir; +import java.util.ArrayList; +import java.util.List; import javax.persistence.*; import java.time.ZonedDateTime; @@ -18,33 +20,40 @@ public class Requirement { @Column(name = "createdAt", nullable = false) private String createdAt; - @Column(name = "completed", nullable = false) - private boolean completed ; - @Column(name = "description", nullable = true) private String description; // FHIR resource which defines the requirement (task, questionnaire, etc) - @JoinColumn(name = "requirement", nullable = false) + @JoinColumn(name = "resource", nullable = false) @OneToOne - private RemsFhir requirement; + private RemsFhir resource; + + @OneToMany(mappedBy="requirement") + private List metRequirements = new ArrayList<>(); @ManyToOne @JoinColumn(name="DRUG_ID") @JsonIgnore private Drug drug; + @OneToMany(mappedBy="parentRequirement", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + private List childRequirements = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="PARENT_REQUIREMENT") + @JsonIgnore + private Requirement parentRequirement; + public Requirement() { this.createdAt = ZonedDateTime.now().format(DateTimeFormatter.ofPattern( "uuuu.MM.dd.HH.mm.ss" )); - this.completed = false; } - public RemsFhir getRequirement() { - return this.requirement; + public RemsFhir getResource() { + return this.resource; } - public void setRequirement(RemsFhir requirement) { - this.requirement = requirement; + public void setResource(RemsFhir resource) { + this.resource = resource; } public String getCreatedAt() { @@ -55,15 +64,6 @@ public void setCreatedAt(String createdAt) { this.createdAt = createdAt; } - public boolean isCompleted() { - return completed; - } - - public void setCompleted(boolean completed) { - this.completed = completed; - } - - public String getDescription() { return description; } @@ -80,4 +80,36 @@ public void setDrug(Drug drug) { this.drug = drug; } + public List getChildren() { + return this.childRequirements; + } + + public void setChildren(List requirements) { + this.childRequirements = requirements; + } + + public void addChild(Requirement requirement) { + this.childRequirements.add(requirement); + } + + public Requirement getParent() { + return this.parentRequirement; + } + + public void setParent(Requirement requirement) { + this.parentRequirement = requirement; + } + + public List getMetRequirements() { + return this.metRequirements; + } + + public void setMetRequirements(List metRequirements) { + this.metRequirements = metRequirements; + } + + public void addChild(MetRequirement metRequirement) { + this.metRequirements.add(metRequirement); + } + } diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/Questionnaire-R4-Prescriber-Enrollment.json b/server/src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/Questionnaire-R4-Prescriber-Enrollment.json new file mode 100644 index 000000000..786ea90f6 --- /dev/null +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/Questionnaire-R4-Prescriber-Enrollment.json @@ -0,0 +1,330 @@ +{ + "resourceType": "Questionnaire", + "id": "TuralioPrescriberEnrollmentForm", + "name": "TuralioPrescriberEnrollmentForm", + "title": "Turalio REMS Prescriber Enrollment Form", + "status": "draft", + "subjectType": [ + "Practitioner" + ], + "date": "2022-05-28", + "publisher": "FDA-REMS", + "item": [ + { + "linkId": "1", + "type": "group", + "text": "Prescriber Information", + "item": [ + { + "linkId": "1.1", + "text": "First Name", + "type": "string", + "required": true + }, + { + "linkId": "1.2", + "text": "Last Name", + "type": "string", + "required": true + }, + { + "linkId": "1.3", + "text": "Middle Initial", + "type": "string", + "required": false + }, + { + "linkId": "1.4", + "text": "Credentials", + "type": "open-choice", + "required": true, + "answerOption": [ + { + "valueCoding": { + "code": "MD", + "display": "MD" + } + }, + { + "valueCoding": { + "code": "DO", + "display": "DO" + } + }, + { + "valueCoding": { + "code": "NP", + "display": "NP" + } + }, + { + "valueCoding": { + "code": "PA", + "display": "PA" + } + }, + { + "valueCoding": { + "code": "Other", + "display": "Other" + } + } + ] + }, + { + "linkId": "1.5", + "text": "Specialty", + "type": "open-choice", + "required": true, + "answerOption": [ + { + "valueCoding": { + "code": "Oncolgy", + "display": "Oncology" + } + }, + { + "valueCoding": { + "code": "Orthopedics", + "display": "Orthopedics" + } + }, + { + "valueCoding": { + "code": "Other", + "display": "Other" + } + } + ] + }, + { + "linkId": "1.6", + "text": "National Provider Identifier (NPI) #", + "type": "string", + "required": true + }, + { + "linkId": "1.7", + "text": "State License #", + "type": "string", + "required": false + }, + { + "linkId": "1.8", + "text": "Practice/Facility Name", + "type": "string", + "required": false + }, + { + "linkId": "1.9", + "text": "Street Address", + "type": "string", + "required": true + }, + { + "linkId": "1.10", + "text": "City", + "type": "string", + "required": true + }, + { + "linkId": "1.11", + "text": "State", + "type": "string", + "required": true + }, + { + "linkId": "1.12", + "text": "ZIP Code", + "type": "string", + "required": true + }, + { + "linkId": "1.13", + "text": "Office Phone Number", + "type": "string", + "required": true + }, + { + "linkId": "1.14", + "text": "Office Fax Number", + "type": "string", + "required": true + }, + { + "linkId": "1.15", + "text": "E-Mail", + "type": "string", + "required": true + }, + { + "linkId": "1.16", + "text": "Perfered Method of Communication", + "type": "open-choice", + "required": false, + "answerOption": [ + { + "valueCoding": { + "code": "Fax", + "display": "Fax" + } + }, + { + "valueCoding": { + "code": "Email", + "display": "Email" + } + }, + { + "valueCoding": { + "code": "Phone", + "display": "Phone" + } + } + ] + }, + { + "linkId": "1.17", + "text": "Perferred Time of Contact", + "type": "open-choice", + "required": false, + "answerOption": [ + { + "valueCoding": { + "code": "AM", + "display": "AM" + } + }, + { + "valueCoding": { + "code": "PM", + "display": "PM" + } + } + ] + } + + ] + }, + { + "linkId": "2", + "type": "group", + "text": "Office Contact Information", + "item": [ + { + "linkId": "2.1", + "text": "Prescribers may grant administrative rights to two (2) Office Contacts which allow them to view, edit, and initiate paperwork related to the TURALIO REMS via the REMS Portal.", + "type": "display" + }, + { + "linkId": "2.2", + "text": "I, the prescriber, grant administrative rights to the office contact(s) listed below and understand that I must review all paperwork and sign prior to submitting to the REMS.", + "type": "display" + }, + { + "linkId": "2.3", + "type": "group", + "text": "Office Contact #1 (Optional)", + "item": [ + { + "linkId": "2.3.1", + "text": "First Name", + "type": "string", + "required": false + }, + { + "linkId": "2.3.2", + "text": "Last Name", + "type": "string", + "required": false + }, + { + "linkId": "2.3.3", + "text": "Office Phone Number", + "type": "string", + "required": false + }, + { + "linkId": "2.3.4", + "text": "Office Fax Number", + "type": "string", + "required": false + }, + { + "linkId": "2.3.5", + "text": "Email", + "type": "string", + "required": false + } + ] + }, + { + "linkId": "2.4", + "type": "group", + "text": "Office Contact #2 (Optional)", + "item": [ + { + "linkId": "2.4.1", + "text": "First Name", + "type": "string", + "required": false + }, + { + "linkId": "2.4.2", + "text": "Last Name", + "type": "string", + "required": false + }, + { + "linkId": "2.4.3", + "text": "Office Phone Number", + "type": "string", + "required": false + }, + { + "linkId": "2.4.4", + "text": "Office Fax Number", + "type": "string", + "required": false + }, + { + "linkId": "2.4.5", + "text": "Email", + "type": "string", + "required": false + } + ] + }, + { + "linkId": "2.5", + "text": "Office Contacts can be updated by visiting www.turaliorems.com or contacting the TURALIO REMS Coordinating Center at 1-833-TURALIO (833-887-2546).", + "type": "display" + } + ] + }, + { + "linkId": "3", + "type": "group", + "text": "Prescriber Attestations", + "item": [ + { + "linkId": "3.1", + "text": "By signing this form, I agree TURALIO is only available through the TURALIO REMS and I agree to comply with the following TURALIO REMS requirements: \n\n I have: \n - Reviewed the Prescribing Information, Program Overview and Prescriber Training. \n - Successfully completed the Prescriber Knowledge Assessment and submitted it to the TURALIO REMS. \n\n Before treatment initiation and with the first dose of TURALIO: \n - I understand that I should counsel the patient on the risk of serious and potentially fatal liver injury, and liver test monitoring at baseline and periodically during treatment. \n - I must assess the patient by obtaining baseline liver tests. I must submit the results of the assessment on the Patient Enrollment Form. \n - I must enroll patients in the TURALIO REMS by completing and submitting the Patient Enrollment Form. \n\n During treatment with TURALIO: \n - I must assess the patient by obtaining liver tests weekly for the first 8 weeks, then every 2 weeks for 1 month, then every 3 months and modify the dose of TURALIO as needed in accordance with the Prescribing Information. \n - I must prescribe no more than a 30 days supply for each of the first 3 months of treatment. \n - I must complete the Patient Status Form every month for the first 3 months of treatment, at months 6, 9, and 12 and then every 6 months thereafter while the patient receives TURALIO. \n\n At all times: \n - I must report adverse events of serious and potentially fatal liver injury by submitting the Liver Adverse Event Reporting Form. \n - I understand that Daiichi Sankyo, Inc. and/or its agents may contact me by phone, mail or email to provide or obtain additional information related to the REMS program, including details regarding any reported liver adverse events. \n", + "type": "display", + "readOnly": true + }, + { + "linkId": "3.2", + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/sub-questionnaire", + "valueCanonical": "questionnaire/provider-signature" + } + ], + "type": "display" + } + + ] + } + ] +} \ No newline at end of file diff --git a/server/src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/Questionnaire-R4-Prescriber-Knowledge-Assessment.json b/server/src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/Questionnaire-R4-Prescriber-Knowledge-Assessment.json new file mode 100644 index 000000000..b1071a2b2 --- /dev/null +++ b/server/src/main/java/org/hl7/davinci/endpoint/rems/resources/Turalio/Questionnaire-R4-Prescriber-Knowledge-Assessment.json @@ -0,0 +1,333 @@ +{ + "resourceType": "Questionnaire", + "id": "TuralioPrescriberKnowledgeAssessment", + "name": "TuralioPrescriberKnowledgeAssessment", + "title": "Turalio REMS Prescriber Knowledge Assessment", + "status": "draft", + "subjectType": [ + "Prescriber" + ], + "date": "2022-05-28", + "publisher": "FDA-REMS", + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/cqf-library", + "valueCanonical": "http://hl7.org/fhir/us/davinci-dtr/Library/BasicPractitionerInfo-prepopulation" + } + ], + "item": [ + { + "linkId": "1", + "type": "group", + "text": "Prescriber Information", + "item": [ + { + "linkId": "1.1", + "text": "First Name", + "type": "string", + "required": true, + "extension": [ + { + "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression", + "valueExpression": { + "language": "text/cql", + "expression": "\"BasicClinicalInfoPrepopulation\".EncounterProviderFirstName" + } + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/minLength", + "valueInteger": 2 + } + ] + }, + { + "linkId": "1.2", + "text": "Last Name", + "type": "string", + "required": true, + "extension": [ + { + "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression", + "valueExpression": { + "language": "text/cql", + "expression": "\"BasicClinicalInfoPrepopulation\".EncounterProviderLastName" + } + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/minLength", + "valueInteger": 2 + } + ] + }, + { + "linkId": "1.3", + "text": "Middle Initial", + "type": "string", + "required": false, + "extension": [ + { + "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression", + "valueExpression": { + "language": "text/cql", + "expression": "\"BasicClinicalInfoPrepopulation\".EncounterProviderMiddleInitial" + } + } + ] + }, + { + "linkId": "1.4", + "text": "National Provider Identifier (NPI) #", + "type": "string", + "required": true, + "extension": [ + { + "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression", + "valueExpression": { + "language": "text/cql", + "expression": "\"BasicClinicalInfoPrepopulation\".EncounterProviderNPI" + } + } + ] + }, + { + "linkId": "1.5", + "text": "Phone Number", + "type": "string", + "required": true + }, + { + "linkId": "1.6", + "text": "Fax Number", + "type": "string", + "required": true + }, + { + "linkId": "1.7", + "text": "Email", + "type": "string", + "required": true + } + ] + }, + { + "linkId": "2", + "type": "group", + "text": "Knowledge Assessment: Questions 1-9", + "item": [ + { + "linkId": "2.1", + "text": "1. TURALIO is indicated for the treatment of adult patients with symptomatic tenosynovial giant cell tumor (TGCT) associated with severe morbidity or functional limitations and not amenable to improvement with surgery.", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "true", + "display": "True" + } + }, + { + "valueCoding": { + "code": "false", + "display": "False" + } + } + ] + }, + { + "linkId": "2.2", + "text": "2. TURALIO is contraindicated in patients with hepatic impairment.", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "true", + "display": "True" + } + }, + { + "valueCoding": { + "code": "false", + "display": "False" + } + } + ] + }, + { + "linkId": "2.3", + "text": "3. To prescribe TURALIO, I must enroll each patient in the TURALIO REMS by completing a Patient Enrollment Form with the patient and submitting it to the TURALIO REMS.", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "true", + "display": "True" + } + }, + { + "valueCoding": { + "code": "false", + "display": "False" + } + } + ] + }, + { + "linkId": "2.4", + "text": "4. Before treating each patient with TURALIO, I must", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "Become certified in the TURALIO REMS", + "display": "Become certified in the TURALIO REMS" + } + }, + { + "valueCoding": { + "code": "Counsel the patient regarding the risk of serious and potentially fatal liver injury associated with TURALIO", + "display": "Counsel the patient regarding the risk of serious and potentially fatal liver injury associated with TURALIO" + } + }, + { + "valueCoding": { + "code": "Obtain and review baseline liver tests", + "display": "Obtain and review baseline liver tests" + } + }, + { + "valueCoding": { + "code": "All of the above", + "display": "All of the above" + } + } + ] + }, + { + "linkId": "2.5", + "text": "5. One of the primary counseling messages I must tell my patients before prescribing TURALIO is", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "Do not take TURALIO if you have vision issues", + "display": "Do not take TURALIO if you have vision issues" + } + }, + { + "valueCoding": { + "code": "Patients with renal impairment should not start TURALIO at a reduced dose", + "display": "Patients with renal impairment should not start TURALIO at a reduced dose" + } + }, + { + "valueCoding": { + "code": "There is a risk of liver injury associated with TURALIO and liver monitoring is required prior to treatment initiation and periodically while taking TURALIO", + "display": "There is a risk of liver injury associated with TURALIO and liver monitoring is required prior to treatment initiation and periodically while taking TURALIO" + } + }, + { + "valueCoding": { + "code": "None of the above", + "display": "None of the above" + } + } + ] + }, + { + "linkId": "2.6", + "text": "6. I am required to educate my patients on the signs and symptoms of liver injury and the need to notify me should they experience them.", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "true", + "display": "True" + } + }, + { + "valueCoding": { + "code": "false", + "display": "False" + } + } + ] + }, + { + "linkId": "2.7", + "text": "7. If any dose modifications are required, they must be done in increments of 200 mg.", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "true", + "display": "True" + } + }, + { + "valueCoding": { + "code": "false", + "display": "False" + } + } + ] + }, + { + "linkId": "2.8", + "text": "8. After treatment initiation, I need to monitor liver tests weekly for the first 8 weeks of treatment, every 2 weeks for the next month, and every 3 months thereafter.", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "true", + "display": "True" + } + }, + { + "valueCoding": { + "code": "false", + "display": "False" + } + } + ] + }, + { + "linkId": "2.9", + "text": "9. I must complete a Patient Status Form for each patient taking TURALIO and submit it to the TURALIO REMS:", + "type": "open-choice", + "answerOption": [ + { + "valueCoding": { + "code": "Every month during treatment", + "display": "Every month during treatment" + } + }, + { + "valueCoding": { + "code": "Weekly for 8 weeks of treatment, every 2 weeks for the next month, and every 3 months thereafter", + "display": "Weekly for 8 weeks of treatment, every 2 weeks for the next month, and every 3 months thereafter" + } + }, + { + "valueCoding": { + "code": "Every month for the first 3 months of treatment, month 6, month 9, and month 12 of treatment, and every 6 months thereafter", + "display": "Every month for the first 3 months of treatment, month 6, month 9, and month 12 of treatment, and every 6 months thereafter" + } + }, + { + "valueCoding": { + "code": "Every month for the first 6 months of treatment and every 6 months thereafter", + "display": "Every month for the first 6 months of treatment and every 6 months thereafter" + } + }, + { + "valueCoding": { + "code": "None of the above", + "display": "None of the above" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index 35aa7a934..7af34557e 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -2,6 +2,8 @@ spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: true spring: + h2: + console.enabled: true thymeleaf: cache: false datasource: