Feature 13619 word document custom date fields inclusion#13874
Conversation
📝 WalkthroughWalkthroughAdds enum constant ROOT_GENERAL and includes it in several DocumentWorkflow rootEntityTypes; backend document-template preparation now populates general properties by formatting LocalDate.now() based on property suffix and user locale via a new helper method. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java (2)
296-321: Redundant stream operation —propertyKeyalready comes from the variables set.The stream filter on lines 299-303 searches for
propertyKeyindocumentVariables.getVariables(), butpropertyKeyoriginates from that same set (line 227's loop). TheOptionalwill always be present, making this filtering unnecessary.Additionally, consider:
- Supporting
FormatStyle.LONGandFormatStyle.FULLfor completeness, or document that onlyshort/mediumare valid suffixes.- The method only provides the current date (
LocalDate.now()). If custom/arbitrary dates are needed in the future, the API would need extension.♻️ Proposed simplification
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<String> 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); - } + // Populate general date properties with locale-formatted current date. + // Supported suffixes: .short (default), .medium, .long, .full + // Example: general.date.medium -> formats as medium style date + String dateType = propertyKey.substring(propertyKey.lastIndexOf('.') + 1); + FormatStyle formatStyle; + switch (dateType) { + case "medium": + formatStyle = FormatStyle.MEDIUM; + break; + case "long": + formatStyle = FormatStyle.LONG; + break; + case "full": + formatStyle = FormatStyle.FULL; + break; + case "short": + default: + formatStyle = FormatStyle.SHORT; + } + String propertyValue = + LocalDate.now().format(DateTimeFormatter.ofLocalizedDate(formatStyle).withLocale(I18nProperties.getUserLanguage().getLocale())); + properties.setProperty(propertyKey, propertyValue); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java` around lines 296 - 321, The fillGeneralValues method performs a redundant stream search for propertyKey inside documentVariables.getVariables() — since propertyKey originates from that set, remove the Optional/stream and operate directly on propertyKey (use propertyKey as generalProperty); also broaden or document accepted date suffixes by handling "long" and "full" in the switch for dateType (map to FormatStyle.LONG and FormatStyle.FULL) or add a comment/Javadoc that only "short"/"medium" are supported; finally, keep the current LocalDate.now() usage but add a TODO/Javadoc on DocumentTemplateFacadeEjb.fillGeneralValues if future support for custom dates is required.
236-240: Consider earlycontinueafter handlingROOT_GENERALto clarify intent.After calling
fillGeneralValues, the code continues toentities.getEntity(rootEntityType)on line 241, which will returnnullforROOT_GENERAL(since there's no backing entity). While theinstanceof HasUuidcheck on line 242 safely handles this, an explicitcontinuewould make the intent clearer and avoid unnecessary processing.Also, the comment on line 236 has a minor phrasing issue: "check if the entity is from a general." — consider rephrasing to "Check if the entity type is ROOT_GENERAL."
♻️ Proposed refactor for clarity
- // check if the entity is from a general. - if (rootEntityType == RootEntityType.ROOT_GENERAL) { - fillGeneralValues(documentVariables, properties, propertyKey); - } - - Object entity = entities.getEntity(rootEntityType); + // Check if the entity type is ROOT_GENERAL (used for general date properties) + if (rootEntityType == RootEntityType.ROOT_GENERAL) { + fillGeneralValues(documentVariables, properties, propertyKey); + continue; + } + + Object entity = entities.getEntity(rootEntityType);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java` around lines 236 - 240, The branch handling RootEntityType.ROOT_GENERAL should short-circuit after filling general values: in the loop where you check rootEntityType, call fillGeneralValues(documentVariables, properties, propertyKey) and then immediately continue to skip the subsequent entities.getEntity(rootEntityType) and instanceof HasUuid checks (which are unnecessary for ROOT_GENERAL); also update the comment from "check if the entity is from a general." to "Check if the entity type is ROOT_GENERAL." to clarify intent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java`:
- Around line 296-321: The fillGeneralValues method performs a redundant stream
search for propertyKey inside documentVariables.getVariables() — since
propertyKey originates from that set, remove the Optional/stream and operate
directly on propertyKey (use propertyKey as generalProperty); also broaden or
document accepted date suffixes by handling "long" and "full" in the switch for
dateType (map to FormatStyle.LONG and FormatStyle.FULL) or add a comment/Javadoc
that only "short"/"medium" are supported; finally, keep the current
LocalDate.now() usage but add a TODO/Javadoc on
DocumentTemplateFacadeEjb.fillGeneralValues if future support for custom dates
is required.
- Around line 236-240: The branch handling RootEntityType.ROOT_GENERAL should
short-circuit after filling general values: in the loop where you check
rootEntityType, call fillGeneralValues(documentVariables, properties,
propertyKey) and then immediately continue to skip the subsequent
entities.getEntity(rootEntityType) and instanceof HasUuid checks (which are
unnecessary for ROOT_GENERAL); also update the comment from "check if the entity
is from a general." to "Check if the entity type is ROOT_GENERAL." to clarify
intent.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5df17505-79a0-4ce4-9011-1ac23992e040
📒 Files selected for processing (3)
sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentWorkflow.javasormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/RootEntityType.javasormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java
|
SonarCloud analysis: https://sonarcloud.io/dashboard?id=SORMAS-Project&pullRequest=13874 |
… 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.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java (2)
297-332: Consider documenting the expected property key format.The implementation assumes property keys follow a pattern like
general.<name>.<formatStyle>(e.g.,general.currentDate.short), but there's no validation of the middle segment. Any property starting withgeneral.will be treated as a date field, which could lead to confusion if users add non-date general properties in the future.Consider either:
- Validating the middle segment (e.g., checking for "currentDate" or "date")
- Adding documentation clarifying that all
general.*properties are currently treated as date fields🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java` around lines 297 - 332, The fillGeneralValues method currently treats any key starting with RootEntityType.ROOT_GENERAL (i.e., "general.*") as a date field; update it to either validate the middle segment or document the expectation: inside fillGeneralValues(DocumentVariables, Properties, String) check that the general property matches the full expected pattern (for example "general.currentDate.(short|medium)" or at least that the middle token equals "currentDate" or "date") before parsing the trailing token as a FormatStyle, and skip or log non-matching keys instead of formatting them; alternatively add a concise comment/Javadoc on fillGeneralValues and the propertyKey parameter explicitly stating that only keys of the form "general.<name>.short|medium" (e.g., "general.currentDate.short") are supported so future contributors/users know the constraint.
307-314: Simplify: The Optional/stream filtering is redundant.The
propertyKeyparameter already originates fromdocumentVariables.getVariables()(line 227) and has been validated to haveROOT_GENERALas its base type (line 230). The stream filter just confirms what's already guaranteed.♻️ Suggested simplification
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<String> 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); + // General properties are allowed only for docx-formatted files. + // Extract the format style suffix from the property key (e.g., "short" from "general.currentDate.short") + String dateType = propertyKey.substring(propertyKey.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); - } + properties.setProperty(propertyKey, propertyValue); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java` around lines 307 - 314, In fillGeneralValues, the stream/Optional that re-filters documentVariables.getVariables() for propertyKey is redundant because propertyKey is already from that list and validated as ROOT_GENERAL; remove the stream block and use propertyKey directly (e.g., treat generalProperty = propertyKey or operate on propertyKey) instead of Optional<String> generalPropertyOpt and its .isPresent() checks, updating any subsequent uses in fillGeneralValues to reference propertyKey so behavior remains the same but simpler.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java`:
- Around line 319-327: The switch handling dateType in DocumentTemplateFacadeEjb
(variable dateType mapping to java.time.format.FormatStyle) only covers "medium"
and "short" and defaults to SHORT, so "long" and "full" inputs are treated
incorrectly; update the switch in the method that assigns formatStyle to include
explicit cases for "long" -> FormatStyle.LONG and "full" -> FormatStyle.FULL
(preserving existing "medium" -> MEDIUM and "short" -> SHORT) so user templates
like $general.currentDate.long or .full receive the correct FormatStyle; keep
the default behavior reasonable (e.g., default to SHORT or throw/handle unknown
values consistently).
---
Nitpick comments:
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java`:
- Around line 297-332: The fillGeneralValues method currently treats any key
starting with RootEntityType.ROOT_GENERAL (i.e., "general.*") as a date field;
update it to either validate the middle segment or document the expectation:
inside fillGeneralValues(DocumentVariables, Properties, String) check that the
general property matches the full expected pattern (for example
"general.currentDate.(short|medium)" or at least that the middle token equals
"currentDate" or "date") before parsing the trailing token as a FormatStyle, and
skip or log non-matching keys instead of formatting them; alternatively add a
concise comment/Javadoc on fillGeneralValues and the propertyKey parameter
explicitly stating that only keys of the form "general.<name>.short|medium"
(e.g., "general.currentDate.short") are supported so future contributors/users
know the constraint.
- Around line 307-314: In fillGeneralValues, the stream/Optional that re-filters
documentVariables.getVariables() for propertyKey is redundant because
propertyKey is already from that list and validated as ROOT_GENERAL; remove the
stream block and use propertyKey directly (e.g., treat generalProperty =
propertyKey or operate on propertyKey) instead of Optional<String>
generalPropertyOpt and its .isPresent() checks, updating any subsequent uses in
fillGeneralValues to reference propertyKey so behavior remains the same but
simpler.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e9ad9ce9-adbd-435b-986a-ee4907d1cc35
📒 Files selected for processing (1)
sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java
...-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java
Show resolved
Hide resolved
|
SonarCloud analysis: https://sonarcloud.io/dashboard?id=SORMAS-Project&pullRequest=13874 |
|
Please note: When opening the document with MS Word, an error message may appear. The file can still be opened as normal, it does not effect the content of the document. We are investigating the reason to provide a fix as soon as possible as part of issue##13847 |
…t-custom-date-fields-inclusion
|
SonarCloud analysis: https://sonarcloud.io/dashboard?id=SORMAS-Project&pullRequest=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.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java (1)
334-335: EvaluateLocalDate.now()once per document.This helper recomputes the date for every placeholder. A template containing multiple
general.currentDate.*fields can produce mixed dates if generation crosses midnight. Capturing the date once inpreparePropertiesand passing it through also makes this path straightforward to test.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java` around lines 334 - 335, Capture LocalDate.now() once when preparing properties (e.g., in prepareProperties within DocumentTemplateFacadeEjb) and pass that captured LocalDate (or its formatted string for the user's locale) into the code that builds each placeholder value instead of calling LocalDate.now() repeatedly; update the helper that currently computes propertyValue (the code block that formats LocalDate.now() with DateTimeFormatter.ofLocalizedDate(...).withLocale(I18nProperties.getUserLanguage().getLocale())) to accept the precomputed LocalDate (or preformatted date) so all general.currentDate.* placeholders use the same date and make the path testable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java`:
- Around line 307-336: fillGeneralValues currently treats any key ending in
".{style}" as a general date and only checks the last token; change it to parse
propertyKey (split on '.') and validate all segments: confirm the first segment
equals RootEntityType.ROOT_GENERAL.getEntityName() case-insensitively, confirm
the second segment equals "currentDate" case-insensitively, and confirm a third
segment exists and is one of "long","full","medium","short" (map to FormatStyle
accordingly). If any of these checks fail, return without setting properties;
only then format the date with
DateTimeFormatter.ofLocalizedDate(...).withLocale(I18nProperties.getUserLanguage().getLocale())
and call properties.setProperty(generalProperty, propertyValue). Use the
existing method name fillGeneralValues and the DocumentVariables/propertyKey
inputs to locate the change.
---
Nitpick comments:
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java`:
- Around line 334-335: Capture LocalDate.now() once when preparing properties
(e.g., in prepareProperties within DocumentTemplateFacadeEjb) and pass that
captured LocalDate (or its formatted string for the user's locale) into the code
that builds each placeholder value instead of calling LocalDate.now()
repeatedly; update the helper that currently computes propertyValue (the code
block that formats LocalDate.now() with
DateTimeFormatter.ofLocalizedDate(...).withLocale(I18nProperties.getUserLanguage().getLocale()))
to accept the precomputed LocalDate (or preformatted date) so all
general.currentDate.* placeholders use the same date and make the path testable.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a53494ad-a345-49a1-af2a-1671f3f12602
📒 Files selected for processing (1)
sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java
| 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<String> 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 "long": | ||
| formatStyle = FormatStyle.LONG; | ||
| break; | ||
| case "full": | ||
| formatStyle = FormatStyle.FULL; | ||
| break; | ||
| 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); |
There was a problem hiding this comment.
Validate the full general placeholder, not just its last segment.
The rest of this class gets here via case-insensitive root matching, but this helper only accepts lowercase general. and then treats any general.* key as “current date in some style” by looking only at the final token. That means $General.currentDate.short stays unresolved, while typos like $general.curentDate.full still render today’s date. Parse propertyKey directly, compare the expected segments case-insensitively, and return for unknown names / formats instead of defaulting them to SHORT.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/docgeneration/DocumentTemplateFacadeEjb.java`
around lines 307 - 336, fillGeneralValues currently treats any key ending in
".{style}" as a general date and only checks the last token; change it to parse
propertyKey (split on '.') and validate all segments: confirm the first segment
equals RootEntityType.ROOT_GENERAL.getEntityName() case-insensitively, confirm
the second segment equals "currentDate" case-insensitively, and confirm a third
segment exists and is one of "long","full","medium","short" (map to FormatStyle
accordingly). If any of these checks fail, return without setting properties;
only then format the date with
DateTimeFormatter.ofLocalizedDate(...).withLocale(I18nProperties.getUserLanguage().getLocale())
and call properties.setProperty(generalProperty, propertyValue). Use the
existing method name fillGeneralValues and the DocumentVariables/propertyKey
inputs to locate the change.
|
SonarCloud analysis: https://sonarcloud.io/dashboard?id=SORMAS-Project&pullRequest=13874 |
Fixes:
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.
Summary by CodeRabbit