package edu.gatech.i3l.fhir.dstu2.entities; import static ca.uhn.fhir.model.dstu2.resource.MedicationOrder.SP_ENCOUNTER; import static ca.uhn.fhir.model.dstu2.resource.MedicationOrder.SP_MEDICATION; import static ca.uhn.fhir.model.dstu2.resource.MedicationOrder.SP_PATIENT; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.regex.Pattern; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import org.hibernate.envers.Audited; import org.hl7.fhir.instance.model.Reference; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt; import ca.uhn.fhir.model.dstu2.composite.CodingDt; import ca.uhn.fhir.model.dstu2.composite.PeriodDt; import ca.uhn.fhir.model.dstu2.composite.RangeDt; import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt; import ca.uhn.fhir.model.dstu2.composite.SimpleQuantityDt; import ca.uhn.fhir.model.dstu2.resource.MedicationOrder; import ca.uhn.fhir.model.dstu2.resource.MedicationOrder.DispenseRequest; import ca.uhn.fhir.model.dstu2.resource.MedicationOrder.DosageInstruction; import ca.uhn.fhir.model.primitive.DateTimeDt; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.InstantDt; import edu.gatech.i3l.fhir.jpa.entity.IResourceEntity; import edu.gatech.i3l.omop.enums.Omop4ConceptsFixedIds; import edu.gatech.i3l.omop.mapping.OmopConceptMapping; import edu.gatech.i3l.omop.mapping.StaticVariables; @Entity @Audited @DiscriminatorValue("PrescriptionWritten") public final class MedicationOrderView extends DrugExposure { public static final String RES_TYPE = "MedicationOrder"; @ManyToOne(cascade = { CascadeType.ALL }) @JoinColumn(name = "person_id", nullable = false) @NotNull private PersonComplement person; /** * For this entity, drug type (name of the concept) is Prescription Written; * it is declared with id 38000177 and vocabulary_id 36, in an Omop v4.0 * compliant database, but this implementation is database independent, * since we use {@link OmopConceptMapping} to gather the information in the * database. */ @ManyToOne(cascade = { CascadeType.MERGE }) @JoinColumn(name = "drug_type_concept_id", nullable = false) @NotNull private Concept drugExposureType; /** * Reflects the date the prescription was written. * * @fhir dateWritten */ @Column(name = "drug_exposure_start_date", nullable = false) @NotNull private Date startDate; @Column(name = "drug_exposure_end_date", nullable = true) private Date endDate; /** * @fhir prescriber */ @ManyToOne(cascade = { CascadeType.ALL }) @JoinColumn(name = "provider_id") private Provider prescribingProvider; /** * @fhir encounter */ @ManyToOne(cascade = { CascadeType.ALL }) @JoinColumn(name = "visit_occurrence_id") private VisitOccurrence visitOccurrence; /** * @notice Note that this is not a direct reference to a specific condition * record, {@link ConditionOccurrence}, in the condition table, but * rather a condition concept in the vocabulary. * @fhir reason */ // @ManyToOne(cascade = { CascadeType.MERGE }) // @JoinColumn(name = "relevant_condition_concept_id") // private Concept relevantCondition; // TODO check other cases where a Concept // can be taken as COndition /* ***************************** * ATTRIBUTES FOR DISPENSE *****************************/ /** * RxNorm. Generally in concept class 'Clinical Drug'. */ @ManyToOne(cascade = { CascadeType.MERGE }) @JoinColumn(name = "drug_concept_id", nullable = false) @NotNull private Concept medication; /** * @fhir quantity */ @Column(name = "quantity") private BigDecimal quantity; /** * The period of validity of the prescription, in days, counting from the * initial date of this prescription. * * @fhir validityPeriod */ @Column(name = "days_supply") private Integer daysSupply; /** * @omop The number of refills after the initial prescription. The initial * prescription is not counted, values start with 0. * @fhir numberOfRepeatsAllowed */ @Column(name = "refills") @Min(0L) private Integer refills; /* * ******************************** END ATTRIBUTES FOR DISPENSE ********************************/ public PersonComplement getPerson() { return person; } public void setPerson(PersonComplement person) { this.person = person; } public Concept getMedication() { return medication; } public void setMedication(Concept medication) { this.medication = medication; } public Concept getDrugExposureType() { return drugExposureType; } public void setDrugExposureType(Concept drugExposureType) { this.drugExposureType = drugExposureType; } public BigDecimal getQuantity() { return quantity; } public void setQuantity(BigDecimal quantity) { this.quantity = quantity; } public Date getStartDate() { return startDate; } public void setStartDate(Date startDate) { this.startDate = startDate; } public Date getEndDate() { return endDate; } public void setEndDate(Date endDate) { this.endDate = endDate; } public Provider getPrescribingProvider() { return prescribingProvider; } public void setPrescribingProvider(Provider prescribingProvider) { this.prescribingProvider = prescribingProvider; } public VisitOccurrence getVisitOccurrence() { return visitOccurrence; } public void setVisitOccurrence(VisitOccurrence visitOccurrence) { this.visitOccurrence = visitOccurrence; } // public Concept getRelevantCondition() { // return relevantCondition; // } // // public void setRelevantCondition(Concept relevantCondition) { // this.relevantCondition = relevantCondition; // } // public Integer getDaysSupply() { return daysSupply; } public void setDaysSupply(Integer daysSupply) { this.daysSupply = daysSupply; } public Integer getRefills() { return refills; } public void setRefills(Integer refills) { this.refills = refills; } @Override public FhirVersionEnum getFhirVersion() { return FhirVersionEnum.DSTU2; } @Override public String getResourceType() { return RES_TYPE; } @Override public InstantDt getUpdated() { // TODO Auto-generated method stub return null; } @Override public String translateSearchParam(String theSearchParam) { switch (theSearchParam) { case SP_ENCOUNTER: return "visitOccurrence"; case SP_PATIENT: return "person"; case SP_MEDICATION: return "medication.name"; default: break; } return theSearchParam; } @Override public IResource getRelatedResource() { MedicationOrder resource = new MedicationOrder(); resource.setId(this.getIdDt()); resource.setDateWritten(new DateTimeDt(this.startDate)); /* Begin Setting Dispense */ // ResourceReferenceDt medicationRef = new ResourceReferenceDt(new // IdDt("Medication", this.medication.getId())); // Adding medication to Contained. CodingDt medCoding = new CodingDt(this.getMedication().getVocabulary().getSystemUri(), this.getMedication().getConceptCode()); medCoding.setDisplay(this.getMedication().getName()); List<CodingDt> codingList = new ArrayList<CodingDt>(); codingList.add(medCoding); CodeableConceptDt codeDt = new CodeableConceptDt(); codeDt.setCoding(codingList); resource.setMedication(codeDt); // // Medication medResource = new Medication(); // // No ID set // medResource.setCode(codeDt); // // // Medication reference. This should point to the contained resource. // ResourceReferenceDt medRefDt = new ResourceReferenceDt(); // medRefDt.setDisplay(this.getMedication().getName()); // // Resource reference set, but no ID // medRefDt.setResource(medResource); // // resource.setMedication(medRefDt); // End of contained medication. // resource.setMedication(medicationRef); DispenseRequest dispense = new DispenseRequest(); dispense.setMedication(codeDt); // dispense.setMedication(medicationRef); // dispense.setMedication(medRefDt); if (this.refills != null) dispense.setNumberOfRepeatsAllowed(this.refills); if (this.quantity != null) { dispense.setQuantity(new SimpleQuantityDt(this.quantity.doubleValue())); } // setting validity Calendar c = Calendar.getInstance(); c.setTime(this.startDate); PeriodDt period = new PeriodDt(); period.setStart(new DateTimeDt(c.getTime())); if (this.endDate != null) { c.setTime(this.endDate); period.setEnd(new DateTimeDt(c.getTime())); } if (this.daysSupply != null) { c.add(Calendar.DAY_OF_MONTH, this.daysSupply); period.setEnd(new DateTimeDt(c.getTime())); } dispense.setValidityPeriod(period); resource.setDispenseRequest(dispense); /* End Setting Dispense */ if (this.visitOccurrence != null) { resource.setEncounter( new ResourceReferenceDt(new IdDt(VisitOccurrence.RES_TYPE, this.visitOccurrence.getId()))); } ResourceReferenceDt patientRef = new ResourceReferenceDt(new IdDt(Person.RES_TYPE, this.person.getId())); patientRef.setDisplay(this.person.getNameAsSingleString()); resource.setPatient(patientRef); // if (this.relevantCondition != null) // // FIXME the reference above doesn't corresponde to a // // ResourceEntity; it should be a reference to Resource Condition // resource.setReason(new ResourceReferenceDt(new IdDt("Condition", this.relevantCondition.getId()))); if (this.prescribingProvider != null) { ResourceReferenceDt prescriberRef = new ResourceReferenceDt(new IdDt(Provider.RESOURCE_TYPE, this.prescribingProvider.getId())); prescriberRef.setDisplay(this.prescribingProvider.getProviderName()); resource.setPrescriber(prescriberRef); } Double doseValue = this.getEffectiveDrugDose(); if (doseValue != null && doseValue >= 0.0) { DosageInstruction dosage = new DosageInstruction(); Concept myUnitConcept = this.getDoseUnitConcept(); SimpleQuantityDt dose; if (myUnitConcept != null) { dose = new SimpleQuantityDt(doseValue, "http://unitsofmeasure.org", myUnitConcept.getName()); dose.setCode(myUnitConcept.getConceptCode()); } else { dose = new SimpleQuantityDt(doseValue); } dosage.setDose(dose); resource.addDosageInstruction(dosage); } // DrugExposureComplement f_drug = this.getComplement(); // if (f_drug != null) { // DosageInstruction dosage = new DosageInstruction(); // // QuantityDt dose = new QuantityDt(); // if (f_drug.getDose() != null && Pattern.matches(StaticVariables.fpRegex, f_drug.getDose())) { // Double doseValue = Double.valueOf(f_drug.getDose()); // Will not // // throw // // NumberFormatException // SimpleQuantityDt dose = new SimpleQuantityDt(doseValue, "http://unitsofmeasure.org", // this.getComplement().getUnit()); // dosage.setDose(dose); // resource.addDosageInstruction(dosage); // } // } return resource; } @Override public IResourceEntity constructEntityFromResource(IResource resource) { MedicationOrder medicationOrder = (MedicationOrder) resource; /* Set patient */ ResourceReferenceDt patientResource = medicationOrder.getPatient(); if (patientResource == null) return null; // We have to have a patient // Long patientRef = patientResource.getReference().getIdPartAsLong(); PersonComplement person = PersonComplement.searchAndUpdate(patientResource); if (person == null) return null; // We must have a patient this.setPerson(person); // We are writing to the database. Keep the source so we know where it is coming from if (medicationOrder.getId() != null) { // See if we already have this in the source field. If so, // then we want update not create MedicationOrderView origMed = (MedicationOrderView) OmopConceptMapping.getInstance().loadEntityBySource(MedicationOrderView.class, "MedicationOrderView", "drugSourceValue", medicationOrder.getId().getIdPart()); if (origMed == null) this.setDrugSourceValue(medicationOrder.getId().getIdPart()); else this.setId(origMed.getId()); } /* Set drup exposure type */ this.drugExposureType = new Concept(); this.drugExposureType.setId(Omop4ConceptsFixedIds.PRESCRIPTION_WRITTEN.getConceptId()); /* Set start date of prescription */ this.startDate = medicationOrder.getDateWritten(); // if (patientRef != null) { // PersonComplement person = (PersonComplement) OmopConceptMapping.getInstance() // .loadEntityById(PersonComplement.class, patientRef); // if (person != null) { // this.setPerson(person); // } else { // // See if we have already received this. // person = (PersonComplement) OmopConceptMapping.getInstance() // .loadEntityBySource(PersonComplement.class, "PersonComplement", "personSourceValue", patientRef.toString()); // if (person != null) { // this.setPerson(person); // } else { // this.person = new PersonComplement(); // this.person.setPersonSourceValue(patientRef.toString()); // } // } // } else { // // Patient is not required field. But, OMOP requires it. If we // // no Patient, return null. // return null; // } /* Set VisitOccurrence */ ResourceReferenceDt visitResRef = medicationOrder.getEncounter(); if (visitResRef != null) { Long encounterRef = visitResRef.getReference().getIdPartAsLong(); // // WebApplicationContext myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext(); // EntityManager entityManager = myAppCtx.getBean("myBaseDao", BaseFhirDao.class).getEntityManager(); if (encounterRef != null) { VisitOccurrence visitOccurrence = VisitOccurrence.searchAndUpdate(encounterRef, startDate, null, this.person); if (visitOccurrence != null) this.setVisitOccurrence(visitOccurrence); // See if this exists. // VisitOccurrence visitOccurrence = // (VisitOccurrence) OmopConceptMapping.getInstance().loadEntityById(VisitOccurrence.class, encounterRef); // if (visitOccurrence != null) { // this.setVisitOccurrence(visitOccurrence); // } else { // // Check source column to see if we have received this before. // visitOccurrence = (VisitOccurrence) OmopConceptMapping.getInstance() // .loadEntityBySource(VisitOccurrence.class, "VisitOccurrence", "visitSourceValue", encounterRef.toString()); // if (visitOccurrence != null) { // this.setVisitOccurrence(visitOccurrence); // } else { // this.visitOccurrence = new VisitOccurrence(); // this.visitOccurrence.setVisitSourceValue(encounterRef.toString()); // this.visitOccurrence.setStartDate(startDate); // this.visitOccurrence.setEndDate(startDate); // this.visitOccurrence.setPerson(this.person); // } // } } } /* Set Medication */ Concept medication = new Concept(); if (medicationOrder.getMedication() instanceof CodeableConceptDt) { CodeableConceptDt codeDt = (CodeableConceptDt) medicationOrder.getMedication(); CodingDt medCoding = codeDt.getCodingFirstRep(); if (medCoding != null) { // this.medication = new Concept(); // String systemUri = medCoding.getSystem(); String code = medCoding.getCode(); medication.setId(OmopConceptMapping.getInstance().get(code)); } } else if (medicationOrder.getMedication() instanceof ResourceReferenceDt) { Reference medicationRef = (Reference) medicationOrder.getMedication(); String medId = medicationRef.getId(); if (Pattern.matches(StaticVariables.fpRegex, medId)) { medication.setId(Long.valueOf(medId)); } } this.setMedication(medication); // OMOP can handle only one dosage. // DrugExposureComplement f_drug = new DrugExposureComplement(); /* dosageInstruction */ DosageInstruction dosageInstruction = medicationOrder.getDosageInstructionFirstRep(); if (dosageInstruction.getDose() instanceof RangeDt) { // This is doseRange } else if (dosageInstruction.getDose() instanceof SimpleQuantityDt) { SimpleQuantityDt doseQty = (SimpleQuantityDt) dosageInstruction.getDose(); this.setEffectiveDrugDose(doseQty.getValue().doubleValue()); this.setDoseUnitSourceValue(doseQty.getUnit()); String doseUnitCode = null; String doseCode = doseQty.getCode(); String doseUnit = doseQty.getUnit(); if (doseCode != null && !doseCode.isEmpty()) { doseUnitCode = doseCode; } else if (doseUnit != null && !doseUnit.isEmpty()) { doseUnitCode = doseUnit; } if (doseUnitCode != null && !doseUnitCode.isEmpty()) { Long unitConceptId = OmopConceptMapping.getInstance().get(doseUnitCode); Concept myUnitConcept; if (unitConceptId > 0) { myUnitConcept = new Concept(unitConceptId); this.setDoseUnitConcept(myUnitConcept); } } // f_drug.setDose(doseQty.getValue().toString()); // f_drug.setUnit(doseQty.getUnit()); } // this.setComplement(f_drug); /* dispense */ DispenseRequest dispenseRequest = medicationOrder.getDispenseRequest(); if (dispenseRequest != null) { Integer refills = dispenseRequest.getNumberOfRepeatsAllowed(); if (refills != null) { this.setRefills(refills); } else { this.setRefills(0); } SimpleQuantityDt qty = dispenseRequest.getQuantity(); if (qty != null) { this.setQuantity(qty.getValue()); } else { this.setQuantity(BigDecimal.ZERO); } if (this.startDate == null) { PeriodDt validPeriod = dispenseRequest.getValidityPeriod(); if (validPeriod != null) { this.startDate = validPeriod.getStart(); } } } ResourceReferenceDt medOrderRef = medicationOrder.getPrescriber(); if (medOrderRef != null) { if (!medOrderRef.isEmpty()) { Provider provider = Provider.searchAndUpdate(medOrderRef); if (provider != null) { this.setPrescribingProvider(provider); } } // Long prescriberID = medOrderRef.getReference().getIdPartAsLong(); // if (prescriberID != null) { // Provider provider = (Provider) OmopConceptMapping.getInstance().loadEntityById(Provider.class, prescriberID); // if (provider != null) { // this.setPrescribingProvider(provider); // } else { // // See the source field and find if we have received this before // provider = (Provider) OmopConceptMapping.getInstance().loadEntityBySource(Provider.class, "Provider", "providerSourceValue", prescriberID.toString()); // if (provider != null) { // this.setPrescribingProvider(provider); // } else { // // We don't have provider... Create one. // this.prescribingProvider = new Provider(); // this.prescribingProvider.setProviderSourceValue(prescriberID.toString()); // } // } // } } return this; } }