-
Notifications
You must be signed in to change notification settings - Fork 10
Fix logo and address not showing in Sticker #3
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
Changes from all commits
0d006e9
1aed602
6d6f03a
1fdce7f
c405768
f82dddc
bb58b1f
4a533f9
16233d6
317aef0
6427674
aa3aac8
85f8aa8
71ad294
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,13 +9,15 @@ | |
| */ | ||
| package org.openmrs.module.patientdocuments.renderer; | ||
|
|
||
| import static org.apache.commons.lang.StringUtils.isBlank; | ||
| import static org.apache.commons.lang.StringUtils.isNotBlank; | ||
| import static org.openmrs.module.patientdocuments.reports.PatientIdStickerReportManager.DATASET_KEY_STICKER_FIELDS; | ||
|
|
||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.io.OutputStream; | ||
| import java.util.Arrays; | ||
| import java.util.Base64; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
@@ -46,6 +48,7 @@ | |
| import org.openmrs.module.reporting.report.renderer.RenderingException; | ||
| import org.openmrs.module.reporting.report.renderer.ReportDesignRenderer; | ||
| import org.openmrs.module.reporting.report.renderer.ReportRenderer; | ||
| import org.openmrs.util.OpenmrsUtil; | ||
| import org.springframework.stereotype.Component; | ||
| import org.w3c.dom.Document; | ||
| import org.w3c.dom.Element; | ||
|
|
@@ -113,6 +116,10 @@ protected String getStringValue(DataSetRow row, DataSetColumn column) { | |
|
|
||
| @Override | ||
| public void render(ReportData results, String argument, OutputStream out) throws IOException, RenderingException { | ||
| render(results, argument, out, null); | ||
| } | ||
|
|
||
| public void render(ReportData results, String argument, OutputStream out, byte[] defaultLogoBytes) throws IOException, RenderingException { | ||
| DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); | ||
| DocumentBuilder docBuilder; | ||
| try { | ||
|
|
@@ -137,7 +144,7 @@ public void render(ReportData results, String argument, OutputStream out) throws | |
| Element templatePIDElement = createStickerTemplate(doc); | ||
|
|
||
| // Handle header configuration | ||
| configureHeader(doc, templatePIDElement); | ||
| configureHeader(doc, templatePIDElement, defaultLogoBytes); | ||
|
|
||
| // Process data set fields | ||
| processDataSetFields(results, doc, templatePIDElement); | ||
|
|
@@ -210,13 +217,11 @@ private Element createStickerTemplate(Document doc) { | |
| return templatePIDElement; | ||
| } | ||
|
|
||
| private void configureHeader(Document doc, Element templatePIDElement) { | ||
| private void configureHeader(Document doc, Element templatePIDElement, byte[] defaultLogoBytes) { | ||
| Element header = doc.createElement("header"); | ||
| // Handle logo if configured | ||
| String logoUrlPath = getInitializerService().getValueFromKey("report.patientIdSticker.logourl"); | ||
| if (isNotBlank(logoUrlPath)) { | ||
| configureLogo(doc, header, logoUrlPath); | ||
| } | ||
| configureLogo(doc, header, logoUrlPath, defaultLogoBytes); | ||
|
|
||
| boolean useHeader = Boolean.TRUE.equals(getInitializerService().getBooleanFromKey("report.patientIdSticker.header")); | ||
| if (useHeader) { | ||
|
|
@@ -238,22 +243,51 @@ private void configureHeader(Document doc, Element templatePIDElement) { | |
| templatePIDElement.appendChild(i18nStrings); | ||
| } | ||
|
|
||
| private void configureLogo(Document doc, Element header, String logoUrlPath) { | ||
| String logoPath; | ||
| File logoFile = new File(logoUrlPath); | ||
| boolean isValidFile = logoFile.exists() && logoFile.canRead() && logoFile.isAbsolute(); | ||
| /** | ||
| * Configures the logo for the sticker document. | ||
| * | ||
| * Logo resolution priority: | ||
| * 1. Custom logo from absolute filesystem path resolved under {@code OPENMRS_APPLICATION_DATA_DIRECTORY} | ||
| * 2. Default OpenMRS logo as base64 data URI | ||
| * | ||
| * @param doc The XML document | ||
| * @param header The header element to append the logo to | ||
| * @param logoUrlPath User-configured logo path (can be null, absolute, or relative) | ||
| * @throws RenderingException if no valid logo can be found | ||
| */ | ||
| private void configureLogo(Document doc, Element header, String logoUrlPath, byte[] defaultLogoBytes) { | ||
| String logoPath = ""; | ||
|
|
||
| try { | ||
| // 1. Try custom logo | ||
| if (isNotBlank(logoUrlPath)) { | ||
| File logoFile = new File(logoUrlPath); | ||
| if (!logoFile.isAbsolute()) { | ||
| File appDataDir = OpenmrsUtil.getDirectoryInApplicationDataDirectory(""); | ||
| logoFile = new File(appDataDir, logoUrlPath); | ||
| } | ||
| if (logoFile.exists() && logoFile.canRead()) { | ||
| logoPath = logoFile.getAbsolutePath(); | ||
| } | ||
| } | ||
|
|
||
| if (isValidFile) { | ||
| logoPath = logoFile.getAbsolutePath(); | ||
| } else { | ||
| throw new RenderingException("Logo file not found or not accessible: " + logoUrlPath); | ||
| // 2. Fall back to default logo | ||
| if (isBlank(logoPath) && defaultLogoBytes != null && defaultLogoBytes.length > 0) { | ||
| String base64Image = Base64.getEncoder().encodeToString(defaultLogoBytes); | ||
| logoPath = "data:image/png;base64," + base64Image; | ||
| } | ||
| } catch (Exception e) { | ||
| throw new RenderingException("Failed to configure logo", e); | ||
| } | ||
|
|
||
| Element branding = doc.createElement("branding"); | ||
| Element image = doc.createElement("logo"); | ||
| image.setTextContent(logoPath); | ||
| branding.appendChild(image); | ||
| header.appendChild(branding); | ||
| // Create and append logo elements if valid | ||
| if (isNotBlank(logoPath)) { | ||
| Element branding = doc.createElement("branding"); | ||
| Element image = doc.createElement("logo"); | ||
| image.setTextContent(logoPath); | ||
| branding.appendChild(image); | ||
| header.appendChild(branding); | ||
| } | ||
| } | ||
|
|
||
| private Map<String, String> createConfigKeyMap() { | ||
|
|
@@ -365,15 +399,16 @@ && shouldIncludeColumn("patientdocuments.patientIdSticker.fields.secondaryIdenti | |
|
|
||
| // Process address | ||
| if (shouldIncludeColumn("patientdocuments.patientIdSticker.fields.fulladdress")) { | ||
| Map<String, String> addressData = (Map<String, String>) patientData.get("preferredAddress"); | ||
| if (addressData != null) { | ||
| List<Map<String, String>> addressData = (List<Map<String, String>>) patientData.get("addresses"); | ||
| if (addressData != null && !addressData.isEmpty()) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this also related to the logo?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No! This ensures that the address data is pulled from the right variable in the Patient Data object. |
||
| Map<String, String> preferredAddress = addressData.get(0); | ||
| StringBuilder address = new StringBuilder(); | ||
| appendIfNotNull(address, addressData.get("address1")); | ||
| appendIfNotNull(address, addressData.get("address2")); | ||
| appendIfNotNull(address, addressData.get("cityVillage")); | ||
| appendIfNotNull(address, addressData.get("stateProvince")); | ||
| appendIfNotNull(address, addressData.get("country")); | ||
| appendIfNotNull(address, addressData.get("postalCode")); | ||
| appendIfNotNull(address, preferredAddress.get("address1")); | ||
| appendIfNotNull(address, preferredAddress.get("address2")); | ||
| appendIfNotNull(address, preferredAddress.get("cityVillage")); | ||
| appendIfNotNull(address, preferredAddress.get("stateProvince")); | ||
| appendIfNotNull(address, preferredAddress.get("country")); | ||
| appendIfNotNull(address, preferredAddress.get("postalCode")); | ||
|
|
||
| if (address.length() > 0) { | ||
| addField(doc, fields, addressKey, address.toString().trim()); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when the logo is not a png?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @dkayiwa. This is the default fallback logo, which we hardcoded to a PNG file at
DEFAULT_LOGO_CLASSPATH = "/images/openmrs_logo_white_large.png"Are we expecting the default logo format to change from PNG to something else? If so, I can make this more dynamic, but otherwise the hardcoded MIME type should match the hardcoded PNG file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when someone's config has a JPG?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user-supplied logo will be retrieved using its absolute path (step 1 in
configureLogo()) before falling back to the default logo. So if someone configures a JPG in theirreport.patientIdSticker.logourlsetting, the absolute file path to that JPG will be used directly. The MIME type image/png only applies to our hardcoded default fallback logo (openmrs_logo_white_large.png), not to user-supplied images.