Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ch emed epr/emediplan #187

Merged
merged 30 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8e0b553
Added additional logic to ChEmedEprObservation#copyValues to deal wit…
dvribeira Jul 31, 2024
0360371
CH EMED EPR: WIP add support for narrative generation in eMediplan fo…
dvribeira Aug 6, 2024
cf1713e
CH EMED EPR: WIP add support for narrative generation in eMediplan fo…
dvribeira Aug 7, 2024
709989e
CH EMED EPR / WIP support for emediplan export
dvribeira Aug 8, 2024
e29c133
CH EMED EPR: WIP add support for narrative generation in eMediplan fo…
dvribeira Aug 11, 2024
0e251b1
CH EMED EPR / WIP support for emediplan export
dvribeira Aug 12, 2024
1ad1fe0
CH EMED EPR / WIP support for emediplan export
dvribeira Aug 14, 2024
d0f7cd8
CH EMED EPR: WIP add support for narrative generation in eMediplan fo…
dvribeira Aug 16, 2024
63b87d8
CH EMED EPR: WIP add support for narrative generation in eMediplan fo…
dvribeira Aug 19, 2024
c2deaf4
CH EMED EPR: WIP add support for narrative generation in eMediplan fo…
dvribeira Aug 20, 2024
525aa33
Merge branch 'refs/heads/develop' into ch-emed-epr/emediplan
dvribeira Aug 21, 2024
f5543a4
CH EMED EPR / WIP support for emediplan export
dvribeira Aug 26, 2024
705d363
CH EMED EPR / WIP support for emediplan export
dvribeira Aug 29, 2024
ef9cc28
CH EMED EPR / WIP support for emediplan export
dvribeira Aug 29, 2024
1796b80
CH EMED EPR / WIP support for emediplan export
dvribeira Aug 30, 2024
a76e20e
Merge branch 'develop' into ch-emed-epr/emediplan
dvribeira Sep 2, 2024
92738e3
CH EMED EPR: WIP add support for narrative generation in eMediplan fo…
dvribeira Sep 12, 2024
ceb6c36
CH EMED EPR / WIP support for emediplan export
dvribeira Sep 12, 2024
0e57ea0
CH EMED EPR / WIP support for emediplan export
dvribeira Sep 18, 2024
155660f
CH EMED EPR / WIP support for emediplan export
dvribeira Sep 26, 2024
1022530
CH EMED EPR / WIP support for emediplan export
dvribeira Sep 30, 2024
00aa35d
CH EMED EPR / WIP support for emediplan export
dvribeira Sep 30, 2024
75b5457
CH EMED EPR / WIP support for emediplan export
dvribeira Oct 2, 2024
03405a7
Merge branch 'develop' into ch-emed-epr/emediplan
dvribeira Oct 3, 2024
45dc2d4
[#181] CH EMED EPR / WIP support for emediplan export
dvribeira Oct 3, 2024
3a477e8
CH EMED EPR: CdTyp9.java: added link to spreadsheet with the unit map…
dvribeira Oct 15, 2024
501cb89
CH EMED EPR: fixed ApplicationAtTime#applicationTime, EMediplanPosolo…
dvribeira Oct 15, 2024
06ed167
CH EMED EPR: Improved javadoc for HtmlToPdfAConverter#convert to remi…
dvribeira Oct 16, 2024
1c22a0e
CH EMED EPR: replaced OpenHtmlToPdfAConverter call to PdfRendererBuil…
dvribeira Oct 16, 2024
5c0cc5f
CH EMED EPR: removed NMOL from RegularUnitCodeAmbu enum and from CdTy…
dvribeira Oct 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
package org.projecthusky.communication.ch.camel.chpharm1.requests.query;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.openehealth.ipf.commons.ihe.xds.core.metadata.Code;
import org.openehealth.ipf.commons.ihe.xds.core.metadata.DocumentEntryType;
import org.openehealth.ipf.commons.ihe.xds.core.metadata.TimeRange;

Expand Down Expand Up @@ -44,6 +45,11 @@ public class ChFindMedicationCardQuery extends ChPharmacyDocumentsQuery {
*/
@Nullable
private Boolean includeNonActive;
/**
* Specific paper/print format for the PMLC PDF (original representation).
*/
@Nullable
private Code paperFormat;

/**
* Constructs the query.
Expand Down Expand Up @@ -87,6 +93,10 @@ public void setLanguageCode(@Nullable final String languageCode) {
public Boolean getIncludeNonActive() { return includeNonActive; }
public void setIncludeNonActive(@Nullable final Boolean includeNonActive) {this.includeNonActive = includeNonActive;}

@Nullable
public Code getPaperFormat() { return paperFormat; }
public void setPaperFormat(@Nullable final Code paperFormat) {this.paperFormat = paperFormat;}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
Expand All @@ -95,12 +105,13 @@ public boolean equals(final Object o) {
&& Objects.equals(serviceStart, that.serviceStart)
&& Objects.equals(serviceEnd, that.serviceEnd)
&& Objects.equals(languageCode, that.languageCode)
&& Objects.equals(includeNonActive, that.includeNonActive);
&& Objects.equals(includeNonActive, that.includeNonActive)
&& Objects.equals(paperFormat, that.paperFormat);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), documentEntryTypes, serviceStart, serviceEnd, languageCode, includeNonActive);
return Objects.hash(super.hashCode(), documentEntryTypes, serviceStart, serviceEnd, languageCode, includeNonActive, paperFormat);
}

@Override
Expand All @@ -111,6 +122,7 @@ public String toString() {
", serviceEnd=" + this.serviceEnd +
", languageCode='" + this.languageCode + '\'' +
", includeNonActive='" + this.includeNonActive + '\'' +
", paperFormat='" + this.paperFormat + '\'' +
", type=" + this.type +
", homeCommunityId='" + this.homeCommunityId + '\'' +
", extraParameters=" + this.extraParameters +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
package org.projecthusky.communication.ch.camel.chpharm1.transform.requests.query;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.openehealth.ipf.commons.ihe.xds.core.metadata.Code;
import org.openehealth.ipf.commons.ihe.xds.core.metadata.Hl7v2Based;
import org.projecthusky.communication.ch.camel.chpharm1.requests.query.ChFindMedicationCardQuery;
import org.openehealth.ipf.commons.ihe.xds.core.ebxml.EbXMLAdhocQueryRequest;
import org.openehealth.ipf.commons.ihe.xds.core.transform.requests.query.QuerySlotHelper;
Expand All @@ -29,6 +31,7 @@ public class ChFindMedicationCardQueryTransformer extends ChPharmacyDocumentsQue
*/
public static final String DOC_ENTRY_LANGUAGE_CODE = "$XDSDocumentEntryLanguageCode";
public static final String PMLC_QUERY_INCLUDE_NON_ACTIVE = "$PMLCIncludeNonActive";
public static final String PMLC_QUERY_PAPER_FORMAT = "$PMLCPaperFormat";

/**
* Transforms the query into its EbXML representation.
Expand Down Expand Up @@ -64,6 +67,11 @@ public void toEbXML(@Nullable final ChFindMedicationCardQuery query,
if (query.getIncludeNonActive() != null) {
ebXML.addSlot(PMLC_QUERY_INCLUDE_NON_ACTIVE, QuerySlotHelper.encodeAsString(query.getIncludeNonActive().toString()));
}

if (query.getPaperFormat() != null) {

ebXML.addSlot(PMLC_QUERY_PAPER_FORMAT, QuerySlotHelper.encodeAsString(Hl7v2Based.render(query.getPaperFormat())));
}
}

/**
Expand Down Expand Up @@ -95,5 +103,6 @@ public void fromEbXML(@Nullable final ChFindMedicationCardQuery query,

query.setLanguageCode(QuerySlotHelper.decodeString(ebXML.getSingleSlotValue(DOC_ENTRY_LANGUAGE_CODE)));
query.setIncludeNonActive(Boolean.valueOf(QuerySlotHelper.decodeString(ebXML.getSingleSlotValue(PMLC_QUERY_INCLUDE_NON_ACTIVE))));
query.setPaperFormat(Hl7v2Based.parse(QuerySlotHelper.decodeString(ebXML.getSingleSlotValue(PMLC_QUERY_PAPER_FORMAT)), Code.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hl7.fhir.r4.model.*;
import org.projecthusky.fhir.emed.ch.common.annotation.ExpectsValidResource;
import org.projecthusky.fhir.emed.ch.common.enums.ReligiousAffiliation;
import org.projecthusky.fhir.emed.ch.common.error.InvalidEmedContentException;
import org.projecthusky.fhir.emed.ch.common.util.FhirDateTimes;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

Expand Down Expand Up @@ -187,6 +191,101 @@ public Identifier addIdentifier(final String system,
.setValue(value);
}

/**
* Resolves the language of correspondence (i.e. preferred communication language) of the patient.
* @return the preferred patient component with the language of correspondence.
*/
public @Nullable PatientCommunicationComponent resolveLanguageOfCorrespondence() {
return getCommunication().stream().filter( com -> com != null && com.getPreferred()).findAny().orElse(null);
}

/**
* Fetches the list of contact points which are an email address.
* @return The list of contact points.
*/
public List<@NonNull ContactPoint> resolveEmailAddresses() {
return resolveTelecom(ContactPoint.ContactPointSystem.EMAIL);
}

/**
* Fetches the list of email addresses values. It does not check their period.
* @return The list of email addresses values.
*/
public List<@NonNull String> resolveEmailAddressesAsStrings() {
return resolveEmailAddressesAsStrings(false);
}

/**
* Fetches the list of email address values, optionally checking if the period is valid at the moment.
* @param activeOnly If true, the method will filter out email address for which the current timestamp is not within
* the period boundaries, if defined.
* @return The list of matching email addresses, as strings.
*/
public List<@NonNull String> resolveEmailAddressesAsStrings(boolean activeOnly) {
return resolveTelecomAsStrings(ContactPoint.ContactPointSystem.EMAIL, activeOnly);
}

/**
* Fetches the list of contact points which are a phone number.
* @return The list of contact points.
*/
public List<@NonNull ContactPoint> resolvePhoneNumbers() {
return resolveTelecom(ContactPoint.ContactPointSystem.PHONE);
}

/**
* Fetches the list of phone number values. It does not check their period.
* @return The list of phone number values as strings.
*/
public List<@NonNull String> resolvePhoneNumbersAsStrings() {
return resolvePhoneNumbersAsStrings(false);
}

/**
* Fetches the list of email address values, optionally checking if the period is valid at the moment.
* @param activeOnly If true, the method will filter out phone numbers for which the current timestamp is not within
* the period boundaries, if defined.
* @return The list of matching email addresses, as strings.
*/
public List<@NonNull String> resolvePhoneNumbersAsStrings(boolean activeOnly) {
return resolveTelecomAsStrings(ContactPoint.ContactPointSystem.PHONE, activeOnly);
}

/**
* Fetches the list of telecom contact point values for the specified system and optionally checking whether they
* are valid at the current time.
*
* @param system The contact point system that must match.
* @param activeOnly Whether to return only contact points for which the current timestamp is within the specified
* boundaries (if any).
* @return The list of strings with the matching contact points values.
*/
private List<@NonNull String> resolveTelecomAsStrings(final ContactPoint.ContactPointSystem system,
boolean activeOnly) {
return resolveTelecom(system).stream().filter(telecom -> {
if (telecom.hasValue()) {
if (activeOnly) {
if (telecom.hasPeriod() && (telecom.getPeriod().hasStart() || telecom.getPeriod().hasEnd())) {
if (telecom.getPeriod().hasStart() && telecom.getPeriod().getStartElement().getValueAsCalendar().after(Calendar.getInstance()))
return false;
if (telecom.getPeriod().hasEnd() && FhirDateTimes.completeToLatestInstant(telecom.getPeriod().getEndElement()).isBefore(Instant.now()))
return false;
} else return true;
} else return true;
}
return false;
}).map(ContactPoint::getValue).toList();
}

/**
* Gets the list of telecom contact points that match the specified system.
* @param system The specific system for which to fetch all the contact points.
* @return The list of contact points.
*/
private List<@NonNull ContactPoint> resolveTelecom(final ContactPoint.ContactPointSystem system) {
return getTelecom().stream().filter(telecom -> telecom.getSystem() == system).toList();
}

@Override
public ChCorePatientEpr copy() {
final var copy = new ChCorePatientEpr();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
<artifactId>husky-fhir-emed-ch-epr-narrative</artifactId>
<name>Husky FHIR eMedication Switzerland EPR Narrative</name>

<properties>
<openhtmltopdf-version>1.0.10</openhtmltopdf-version>
</properties>

<dependencies>
<dependency>
<groupId>org.projecthusky.fhir.emed.ch</groupId>
Expand All @@ -35,19 +31,21 @@

<!-- HTML to PDF conversion -->
<dependency>
<groupId>com.openhtmltopdf</groupId>
<groupId>io.github.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-core</artifactId> <!-- LGPL -->
<version>${openhtmltopdf-version}</version>
</dependency>
<dependency>
<groupId>com.openhtmltopdf</groupId>
<groupId>io.github.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-pdfbox</artifactId> <!-- LGPL -->
<version>${openhtmltopdf-version}</version>
</dependency>
<dependency>
<groupId>com.openhtmltopdf</groupId>
<groupId>io.github.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-slf4j</artifactId>
<version>${openhtmltopdf-version}</version>
</dependency>
<dependency>
<!-- SVG support plugin. -->
<groupId>io.github.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-svg-support</artifactId>
</dependency>

<dependency>
Expand All @@ -61,6 +59,16 @@
<artifactId>checker-qual</artifactId> <!-- MIT -->
</dependency>

<!-- QR code generator -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
</dependency>

<!-- Tests (EPL 2.0) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand All @@ -72,6 +80,10 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projecthusky.validation.service</groupId>
<artifactId>husky-validation-service</artifactId>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ public enum NarrativeLanguage {
monthPrecisionFormatter,
dayPrecisionFormatter,
hourPrecisionFormatter,
minutePrecisionFormatter;
minutePrecisionFormatter,
emediplanMinutePrecisionFormatter,
emediplanDayPrecisionFormatter;

private final Locale locale;

/**
* Constructor.
Expand All @@ -59,16 +63,21 @@ public enum NarrativeLanguage {
final String displayName) {
this.isoCode = Objects.requireNonNull(isoCode);
this.displayName = Objects.requireNonNull(displayName);
this.locale = new Locale(this.isoCode, "ch");
this.yearPrecisionFormatter =
DateTimeFormatter.ofPattern("yyyy", getLocale()).withZone(ZoneId.systemDefault());
DateTimeFormatter.ofPattern("yyyy", locale).withZone(ZoneId.systemDefault());
this.monthPrecisionFormatter =
DateTimeFormatter.ofPattern("MM/yyyy", getLocale()).withZone(ZoneId.systemDefault());
DateTimeFormatter.ofPattern("MM/yyyy", locale).withZone(ZoneId.systemDefault());
this.dayPrecisionFormatter =
DateTimeFormatter.ofPattern("dd/MM/yyyy", getLocale()).withZone(ZoneId.systemDefault());
DateTimeFormatter.ofPattern("dd/MM/yyyy", locale).withZone(ZoneId.systemDefault());
this.hourPrecisionFormatter =
DateTimeFormatter.ofPattern("dd/MM/yyyy HH", getLocale()).withZone(ZoneId.systemDefault());
DateTimeFormatter.ofPattern("dd/MM/yyyy HH", locale).withZone(ZoneId.systemDefault());
this.minutePrecisionFormatter =
DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm", getLocale()).withZone(ZoneId.systemDefault());
DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm", locale).withZone(ZoneId.systemDefault());
this.emediplanMinutePrecisionFormatter =
DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm", locale).withZone(ZoneId.systemDefault());
this.emediplanDayPrecisionFormatter =
DateTimeFormatter.ofPattern("dd.MM.yyyy", locale).withZone(ZoneId.systemDefault());
}

public String getIsoCode() {
Expand All @@ -83,14 +92,16 @@ public String getDisplayName() {
* Returns the related {@link Locale}.
*/
public Locale getLocale() {
return new Locale(this.isoCode, "ch");
return locale;
}

public DateTimeFormatter getYearPrecisionFormatter() {return yearPrecisionFormatter;}
public DateTimeFormatter getMonthPrecisionFormatter() {return monthPrecisionFormatter;}
public DateTimeFormatter getDayPrecisionFormatter() {return dayPrecisionFormatter;}
public DateTimeFormatter getHourPrecisionFormatter() {return hourPrecisionFormatter;}
public DateTimeFormatter getMinutePrecisionFormatter() {return minutePrecisionFormatter;}
public DateTimeFormatter getEmediplanMinutePrecisionFormatter() {return emediplanMinutePrecisionFormatter;}
public DateTimeFormatter getEmediplanDayPrecisionFormatter() {return emediplanDayPrecisionFormatter;}

/**
* Returns the related {@link LanguageCode}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import org.projecthusky.fhir.emed.ch.epr.narrative.enums.NarrativeLanguage;
import org.projecthusky.fhir.emed.ch.epr.narrative.services.MedicationImageProvider;
import org.projecthusky.fhir.emed.ch.epr.narrative.services.ValueSetEnumNarrativeForPatientService;
import org.projecthusky.fhir.emed.ch.epr.resource.pmlc.ChEmedEprDocumentPmlc;
import org.projecthusky.fhir.emed.ch.epr.resource.pre.ChEmedEprDocumentPre;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumMap;
Expand Down Expand Up @@ -35,7 +36,7 @@ abstract class AbstractNarrativeGenerator {
*/
protected MedicationImageProvider medicationImageProvider = MedicationImageProvider.NO_OP_INSTANCE;

AbstractNarrativeGenerator() throws IOException, ParserConfigurationException {
AbstractNarrativeGenerator() throws IOException {
final Function<String, InputStream> getRes = (final String lang) ->
Objects.requireNonNull(AbstractNarrativeGenerator.class.getResourceAsStream(
"/narrative/translations/Messages." + lang + ".properties"));
Expand All @@ -55,4 +56,25 @@ public void setMedicationImageProvider(@Nullable final MedicationImageProvider m
this.medicationImageProvider = Objects.requireNonNullElse(medicationImageProvider,
MedicationImageProvider.NO_OP_INSTANCE);
}

/**
* Generates the narrative for a medication card and return it as HTML content.
*
* @param document The medication card document.
* @param lang The language of the narrative.
* @return The HTML content of the narrative.
*/
abstract public String generate(final ChEmedEprDocumentPmlc document,
final NarrativeLanguage lang
);

/**
* Generates the narrative for a prescription and return it as HTML content.
*
* @param document The prescription document.
* @param lang The language of the narrative.
* @return The HTML content of the narrative.
*/
abstract public String generate(final ChEmedEprDocumentPre document,
final NarrativeLanguage lang);
}
Loading
Loading