Commit d11db87b authored by Thomas Huster's avatar Thomas Huster
Browse files

[17251] added PrintMedicationHistoryHandler to generate pdf

parent 0c919943
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -336,6 +336,17 @@
               style="push">
         </command>
      </menuContribution>
      <menuContribution
            allPopups="false"
            locationURI="toolbar:ch.elexis.core.ui.medication.views.MedicationView">
         <command
               commandId="ch.elexis.core.ui.PrintMedicationHistory"
               icon="icon://IMG_DOCUMENT_PDF"
               label="Medikation-Verlauf als Pdf"
               style="push"
               tooltip="Medikation-Verlauf als Pdf">
         </command>
      </menuContribution>
   </extension>
      <extension
         point="org.eclipse.ui.preferencePages">
@@ -783,6 +794,11 @@
            id="ch.elexis.core.ui.commands.printContactLabel"
            name="Print address label">
      </command>
      <command
            defaultHandler="ch.elexis.core.ui.commands.PrintMedicationHistoryHandler"
            id="ch.elexis.core.ui.PrintMedicationHistory"
            name="Print medication history">
      </command>
   </extension>
      <extension
            point="ch.elexis.core.ui.KonsExtension">
+123 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xChange="http://informatics.sgam.ch/xChange"
	exclude-result-prefixes="fo">
	<xsl:output method="xml" version="1.0" omit-xml-declaration="no"
		indent="yes" encoding="UTF-8"/>
	<xsl:param name="versionParam" select="'1.0'"/>
	<xsl:param name="current-date" />

	<!-- ========================= -->
	<!-- root element: letter -->
	<!-- ========================= -->
	<xsl:template match="medicationhistory">
		<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
			<fo:layout-master-set>
				<fo:simple-page-master master-name="simpleA4"
					page-height="29.7cm" page-width="21cm" margin-top="2cm"
					margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
					<fo:region-body/>
					<fo:region-after/>
				</fo:simple-page-master>
			</fo:layout-master-set>

			<fo:page-sequence master-reference="simpleA4">
				<fo:static-content flow-name="xsl-region-after">
					<fo:block font-size="8pt" text-align-last="justify"
						width="100%" border-top-style="solid" border-top-width="thin"
						padding="1mm">
						<fo:leader leader-pattern="space"/>
						<fo:character character="&#x20;"/>
						Seite
						<fo:page-number/>
						von
						<fo:page-number-citation ref-id="last-page"/>
					</fo:block>
				</fo:static-content>

				<fo:flow  font-size="10pt" flow-name="xsl-region-body">
					<fo:block font-size="8pt" text-align="right">
						Medikationsverlauf von <xsl:value-of select="patientName"/>, <xsl:value-of select="patientDob"/> erstellt am <xsl:value-of select="$current-date"/>
					</fo:block>

					<fo:block text-align-last="justify"
						width="100%" border-top-style="solid" border-top-width="thin"
						padding="1mm" text-align="left" font-weight="bold"/>
					<fo:block text-align="left" font-size="10pt">
						<fo:table font-size="10pt" table-layout="fixed" width="100%">
							<fo:table-column column-width="15%"/>
							<fo:table-column column-width="15%"/>
							<fo:table-column column-width="55%"/>
							<fo:table-column column-width="15%"/>
            				<fo:table-header>
                				<fo:table-row>
                    				<fo:table-cell>
                            			<fo:block font-weight="bold">
                            			Von
                            			</fo:block>
                        			</fo:table-cell>      
                    				<fo:table-cell>
                            			<fo:block font-weight="bold">
                            			Bis
                            			</fo:block>
                        			</fo:table-cell>      
                    				<fo:table-cell>
                            			<fo:block font-weight="bold">
                            			Medikament
                            			</fo:block>
                        			</fo:table-cell>      
                    				<fo:table-cell>
                            			<fo:block font-weight="bold">
                            			Dosierung
                            			</fo:block>
                        			</fo:table-cell>      
                				</fo:table-row>
            				</fo:table-header>
            				<fo:table-body>
               					<xsl:apply-templates select="history"/>
            				</fo:table-body>
        				</fo:table>
        			</fo:block>
										
					<fo:block id="last-page"/>
				</fo:flow>
			</fo:page-sequence>
		</fo:root>
	</xsl:template>

	<!-- ========================= -->
	<!-- child element: history -->
	<!-- ========================= -->
	<xsl:template match="history">
		  <xsl:variable name="bg-color">
		    <xsl:choose>
		      <xsl:when test="position() mod 2 = 0">white</xsl:when>
		      <xsl:otherwise>lightgrey</xsl:otherwise>
		    </xsl:choose>
		  </xsl:variable>
		<fo:table-row background-color="{$bg-color}">
			<fo:table-cell>
				<fo:block>
					<xsl:value-of select="from"/>
				</fo:block>
			</fo:table-cell>
			<fo:table-cell>
				<fo:block>
					<xsl:value-of select="to"/>
				</fo:block>
			</fo:table-cell>
			<fo:table-cell>
				<fo:block>
					<xsl:value-of select="article"/>
				</fo:block>
			</fo:table-cell>
			<fo:table-cell>
				<fo:block>
					<xsl:value-of select="dosage"/>
				</fo:block>
			</fo:table-cell>
		</fo:table-row>
	</xsl:template>  
	

</xsl:stylesheet>
+239 −0
Original line number Diff line number Diff line
package ch.elexis.core.ui.commands;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.handlers.HandlerUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.slf4j.LoggerFactory;

import ch.elexis.core.data.events.ElexisEventDispatcher;
import ch.elexis.core.model.prescription.EntryType;
import ch.elexis.core.services.IFormattedOutput;
import ch.elexis.core.services.IFormattedOutputFactory;
import ch.elexis.core.services.IFormattedOutputFactory.ObjectType;
import ch.elexis.core.services.IFormattedOutputFactory.OutputType;
import ch.elexis.data.Patient;
import ch.elexis.data.Prescription;
import ch.elexis.data.Query;
import ch.rgw.tools.TimeTool;

public class PrintMedicationHistoryHandler extends AbstractHandler implements IHandler {
	
	private static final String TOOPEN = " ... ";
	
	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException{
		ProgressMonitorDialog progress =
			new ProgressMonitorDialog(HandlerUtil.getActiveShell(event));
		try {
			progress.run(true, false, new IRunnableWithProgress() {
				
				@Override
				public void run(IProgressMonitor monitor)
					throws InvocationTargetException, InterruptedException{
					monitor.beginTask("PDF erzeugen", IProgressMonitor.UNKNOWN);
					Optional<MedicationHistoryLetter> letter = getToPrint();
					if (letter.isPresent()) {
						BundleContext bundleContext =
							FrameworkUtil.getBundle(getClass()).getBundleContext();
						ServiceReference<IFormattedOutputFactory> serviceRef =
							bundleContext.getServiceReference(IFormattedOutputFactory.class);
						if (serviceRef != null) {
							IFormattedOutputFactory service = bundleContext.getService(serviceRef);
							IFormattedOutput outputter = service
								.getFormattedOutputImplementation(ObjectType.JAXB, OutputType.PDF);
							ByteArrayOutputStream pdf = new ByteArrayOutputStream();
							Map<String, String> parameters = new HashMap<>();
							parameters.put("current-date",
								LocalDate.now().format(DateTimeFormatter.ofPattern("dd.MM.yyyy")));
							
							outputter.transform(letter.get(),
								getClass().getResourceAsStream("/rsc/xslt/medhistory2fo.xslt"), pdf,
								parameters);
							bundleContext.ungetService(serviceRef);
							// save and open the file ...
							File file = null;
							FileOutputStream fout = null;
							try {
								file = File.createTempFile("medhistory_", ".pdf");
								fout = new FileOutputStream(file);
								fout.write(pdf.toByteArray());
							} catch (IOException e) {
								Display.getDefault().syncExec(() -> {
									MessageDialog.openError(HandlerUtil.getActiveShell(event),
										"Fehler", "Fehler beim PDF anlegen.\n" + e.getMessage());
								});
								LoggerFactory.getLogger(getClass()).error("Error creating PDF", e);
							} finally {
								if (fout != null) {
									try {
										fout.close();
									} catch (IOException e) {
										// ignore
									}
								}
							}
							if (file != null) {
								Program.launch(file.getAbsolutePath());
							}
						}
					} else {
						Display.getDefault().syncExec(() -> {
							MessageDialog.openInformation(HandlerUtil.getActiveShell(event), "Info",
								"Kein Patient ausgewählt, oder Patient hat keine Medikation.\n");
						});
					}
					monitor.done();
				}
			});
		} catch (InvocationTargetException | InterruptedException e) {
			MessageDialog.openError(HandlerUtil.getActiveShell(event), "Fehler",
				"Fehler beim PDF erzeugen.\n" + e.getMessage());
			LoggerFactory.getLogger(getClass()).error("Error creating PDF", e);
		}
		return null;
	}
	
	@Override
	public boolean isEnabled(){
		return isFopServiceAvailable();
	}
	
	private boolean isFopServiceAvailable(){
		BundleContext bundleContext = FrameworkUtil.getBundle(getClass()).getBundleContext();
		return bundleContext.getServiceReference(IFormattedOutputFactory.class) != null;
	}
	
	public Optional<MedicationHistoryLetter> getToPrint(){
		Patient patient = ElexisEventDispatcher.getSelectedPatient();
		if (patient != null) {
			Query<Prescription> qbe = new Query<Prescription>(Prescription.class);
			qbe.add(Prescription.FLD_PATIENT_ID, Query.EQUALS, patient.getId());
			List<Prescription> list = qbe.execute();
			if (!list.isEmpty()) {
				return Optional.of(MedicationHistoryLetter.of(patient, list));
			}
		}
		return Optional.empty();
	}
	
	@XmlRootElement(name = "medicationhistory")
	private static class MedicationHistoryLetter {
		
		private List<MedicationHistoryItem> history;
		@XmlElement
		private String patientName;
		@XmlElement
		private String patientDob;
		
		private MedicationHistoryLetter(){
			// needed for jaxb
		}
		
		private MedicationHistoryLetter(Patient patient){
			patientName = patient.getLabel(true);
			patientDob = patient.getGeburtsdatum();
			
			history = new ArrayList<>();
		}
		
		public void setHistory(List<MedicationHistoryItem> history){
			this.history = history;
		}
		
		public List<MedicationHistoryItem> getHistory(){
			return history;
		}
		
		public static MedicationHistoryLetter of(Patient patient, List<Prescription> list){
			MedicationHistoryLetter ret = new MedicationHistoryLetter(patient);
			
			for (Prescription prescription : list) {
				if (prescription.getEntryType() != EntryType.RECIPE) {
					Map<TimeTool, String> terms = prescription.getTerms();
					TimeTool[] tts = terms.keySet().toArray(new TimeTool[0]);
					for (int i = 0; i < tts.length - 1; i++) {
						if (i < tts.length - 1) {
							ret.history
								.add(new MedicationHistoryItem(tts[i].toString(TimeTool.DATE_GER),
									tts[i + 1].toString(TimeTool.DATE_GER), prescription));
						} else {
							ret.history.add(new MedicationHistoryItem(
								tts[i].toString(TimeTool.DATE_GER), TOOPEN, prescription));
						}
					}
					ret.history.add(new MedicationHistoryItem(
						tts[tts.length - 1].toString(TimeTool.DATE_GER), TOOPEN, prescription));
				}
			}
			Collections.sort(ret.history);
			
			return ret;
		}
	}
	
	@XmlRootElement(name = "historyitem")
	private static class MedicationHistoryItem implements Comparable<MedicationHistoryItem> {
		
		@XmlTransient
		private TimeTool fromTool;
		
		@XmlElement
		private String from;
		@XmlElement
		private String to;
		@XmlElement
		private String article;
		@XmlElement
		private String dosage;
		
		private MedicationHistoryItem(){
			// needed for jaxb
		}
		
		public MedicationHistoryItem(final String from, final String to, final Prescription p){
			this.from = from;
			this.fromTool = new TimeTool(from);
			this.to = to;
			if (TOOPEN.equals(to) && StringUtils.isNotBlank(p.getEndDate())) {
				this.to = p.getEndDate();
			}
			this.article = p.getArtikel() != null ? p.getArtikel().getLabel() : "?";
			this.dosage = p.getDosis();
		}
		
		@Override
		public int compareTo(MedicationHistoryItem other){
			return other.fromTool.compareTo(fromTool);
		}
	}
}