From 8acecf997522ee4d46fc90aad5b5bb74e8000fb5 Mon Sep 17 00:00:00 2001 From: Karnaiah Pesula Date: Tue, 10 Feb 2026 08:53:51 +0100 Subject: [PATCH 1/3] Implemented custom general properties for dynamic document generation --- .../api/docgeneneration/DocumentWorkflow.java | 36 +++++++++---------- .../api/docgeneneration/RootEntityType.java | 3 +- .../DocumentTemplateFacadeEjb.java | 36 +++++++++++++++++++ 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentWorkflow.java b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentWorkflow.java index 060afed1471..f1b02510734 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentWorkflow.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentWorkflow.java @@ -21,6 +21,7 @@ import static de.symeda.sormas.api.docgeneneration.RootEntityType.ROOT_EVENT_ACTIONS; import static de.symeda.sormas.api.docgeneneration.RootEntityType.ROOT_EVENT_PARTICIPANT; import static de.symeda.sormas.api.docgeneneration.RootEntityType.ROOT_EVENT_PARTICIPANTS; +import static de.symeda.sormas.api.docgeneneration.RootEntityType.ROOT_GENERAL; import static de.symeda.sormas.api.docgeneneration.RootEntityType.ROOT_PATHOGEN_TEST; import static de.symeda.sormas.api.docgeneneration.RootEntityType.ROOT_PERSON; import static de.symeda.sormas.api.docgeneneration.RootEntityType.ROOT_SAMPLE; @@ -54,7 +55,8 @@ public enum DocumentWorkflow { ROOT_USER, ROOT_SAMPLE, ROOT_PATHOGEN_TEST, - ROOT_VACCINATION), + ROOT_VACCINATION, + ROOT_GENERAL), QUARANTINE_ORDER_CONTACT(DocumentWorkflowType.DOCUMENT, "quarantineContact", DOCX, @@ -64,7 +66,8 @@ public enum DocumentWorkflow { ROOT_USER, ROOT_SAMPLE, ROOT_PATHOGEN_TEST, - ROOT_VACCINATION), + ROOT_VACCINATION, + ROOT_GENERAL), QUARANTINE_ORDER_EVENT_PARTICIPANT(DocumentWorkflowType.DOCUMENT, "quarantineEventParticipant", DOCX, @@ -74,14 +77,16 @@ public enum DocumentWorkflow { ROOT_USER, ROOT_SAMPLE, ROOT_PATHOGEN_TEST, - ROOT_VACCINATION), + ROOT_VACCINATION, + ROOT_GENERAL), QUARANTINE_ORDER_TRAVEL_ENTRY(DocumentWorkflowType.DOCUMENT, "quarantineTravelEntry", DOCX, UserRight.DOCUMENT_TEMPLATE_MANAGEMENT, ROOT_TRAVEL_ENTRY, ROOT_PERSON, - ROOT_USER), + ROOT_USER, + ROOT_GENERAL), EVENT_HANDOUT(DocumentWorkflowType.DOCUMENT, "eventHandout", HTML, @@ -127,22 +132,15 @@ public enum DocumentWorkflow { ROOT_TRAVEL_ENTRY, ROOT_PERSON, ROOT_USER), - SURVEY_DOCUMENT(DocumentWorkflowType.DOCUMENT, - "survey", - DOCX, - UserRight.SURVEY_EDIT, - ROOT_CASE, - ROOT_PERSON, - ROOT_USER, - ROOT_SAMPLE), + SURVEY_DOCUMENT(DocumentWorkflowType.DOCUMENT, "survey", DOCX, UserRight.SURVEY_EDIT, ROOT_CASE, ROOT_PERSON, ROOT_USER, ROOT_SAMPLE), SURVEY_EMAIL(DocumentWorkflowType.EMAIL, - Constants.EMAIL_TEMPLATES_FOLDER + "/surveys", - TXT, - UserRight.SURVEY_EDIT, - ROOT_CASE, - ROOT_PERSON, - ROOT_USER, - ROOT_SAMPLE),; + Constants.EMAIL_TEMPLATES_FOLDER + "/surveys", + TXT, + UserRight.SURVEY_EDIT, + ROOT_CASE, + ROOT_PERSON, + ROOT_USER, + ROOT_SAMPLE),; private final DocumentWorkflowType type; private final String templateDirectory; diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/RootEntityType.java b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/RootEntityType.java index 07b8a3f5ff0..dc5d241ef40 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/RootEntityType.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/RootEntityType.java @@ -28,7 +28,8 @@ public enum RootEntityType { ROOT_EVENT_ACTIONS("eventActions"), ROOT_EVENT_PARTICIPANTS("eventParticipants"), ROOT_TRAVEL_ENTRY("travelEntry"), - ROOT_VACCINATION("vaccination"); + ROOT_VACCINATION("vaccination"), + ROOT_GENERAL("general"); private final String entityName; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java index 627307154e5..1144421814b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java @@ -19,7 +19,11 @@ import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.util.List; +import java.util.Optional; import java.util.Properties; import java.util.Set; import java.util.regex.Matcher; @@ -229,6 +233,11 @@ private Properties prepareProperties( continue; } + // check if the entity is from a general. + if (rootEntityType == RootEntityType.ROOT_GENERAL) { + fillGeneralValues(documentVariables, properties, propertyKey); + } + Object entity = entities.getEntity(rootEntityType); if (entity instanceof HasUuid) { if (documentWorkflow.isDocx() || propertyKey.contains(propertySeparator)) { @@ -284,6 +293,33 @@ private Properties prepareProperties( return properties; } + private void fillGeneralValues(DocumentVariables documentVariables, Properties properties, String propertyKey) { + // finding the general property key. Based on the type, formatStyle is deciding. + // general properties are allowed only doc-formatted files. + Optional generalPropertyOpt = documentVariables.getVariables() + .stream() + .filter(e -> e.startsWith(RootEntityType.ROOT_GENERAL.getEntityName() + ".")) + .filter(e -> e.equals(propertyKey)) + .findAny(); + + if (generalPropertyOpt.isPresent()) { + String generalProperty = generalPropertyOpt.get(); + String dateType = generalProperty.substring(generalProperty.lastIndexOf('.') + 1); + FormatStyle formatStyle; + switch (dateType) { + case "medium": + formatStyle = FormatStyle.MEDIUM; + break; + case "short": + default: + formatStyle = FormatStyle.SHORT; + } + String propertyValue = + LocalDate.now().format(DateTimeFormatter.ofLocalizedDate(formatStyle).withLocale(I18nProperties.getUserLanguage().getLocale())); + properties.setProperty(generalProperty, propertyValue); + } + } + private byte[] generateDocumentDocx(File templateFile, Properties properties) throws DocumentTemplateException { return templateEngine.generateDocumentDocx(properties, templateFile); } From b62ac6a585cd8564ce217855ac827130c10f7dec Mon Sep 17 00:00:00 2001 From: Karnaiah Pesula Date: Tue, 10 Mar 2026 11:53:44 +0100 Subject: [PATCH 2/3] Bugfix#13874 Word Document custom Data fields not updating when using email sending. Summary: Providing way to incorporate custom date meaning today's date as "general" properties. Changes: Introduced a new type of variables as general. Custom dates are included as $general.currentDate.short in the word document. Including these changes for different workflows like : QUARANTINE_ORDER_CASE - Document Templates Case, QUARANTINE_ORDER_CONTACT = Document Templates Contact and QUARANTINE_ORDER_EVENT_PARTICIPANT = Document Templates Event Participant Since this is a dynamic date, and comparing the static content in the test cases, couldn't write the test cases. --- .../docgeneration/DocumentTemplateFacadeEjb.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java index 1144421814b..1d0ce4b19ea 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java @@ -234,6 +234,7 @@ private Properties prepareProperties( } // check if the entity is from a general. + // General entities are used for common and dynamic data that can be referenced across different entities. if (rootEntityType == RootEntityType.ROOT_GENERAL) { fillGeneralValues(documentVariables, properties, propertyKey); } @@ -293,6 +294,16 @@ private Properties prepareProperties( return properties; } + /** + * Fills general values into the properties based on the provided document variables and properties. + * + * @param documentVariables + * The document variables to use for filling general values. + * @param properties + * The properties to fill with general values. + * @param propertyKey + * The property key to use for general value retrieval. + */ private void fillGeneralValues(DocumentVariables documentVariables, Properties properties, String propertyKey) { // finding the general property key. Based on the type, formatStyle is deciding. // general properties are allowed only doc-formatted files. From d05d5abafe057be0e9aa43a07e023649b26df87b Mon Sep 17 00:00:00 2001 From: Karnaiah Pesula Date: Tue, 10 Mar 2026 16:32:19 +0100 Subject: [PATCH 3/3] Fixes: Bugfix# 13874 Summary: Supports different formats for dates in the documents. Changes: Include multiple formats like, long, full, medium and short types of dates for the document templates. --- .../backend/docgeneration/DocumentTemplateFacadeEjb.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java index 1d0ce4b19ea..3b7e8d52a3f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java @@ -318,6 +318,12 @@ private void fillGeneralValues(DocumentVariables documentVariables, Properties p String dateType = generalProperty.substring(generalProperty.lastIndexOf('.') + 1); FormatStyle formatStyle; switch (dateType) { + case "long": + formatStyle = FormatStyle.LONG; + break; + case "full": + formatStyle = FormatStyle.FULL; + break; case "medium": formatStyle = FormatStyle.MEDIUM; break;