Skip to content

Bugfix 13843 merging case survey token issue#13873

Merged
KarnaiahPesula merged 8 commits intodevelopmentfrom
bugfix-13843-merging-case-survey-token-issue
Mar 11, 2026
Merged

Bugfix 13843 merging case survey token issue#13873
KarnaiahPesula merged 8 commits intodevelopmentfrom
bugfix-13843-merging-case-survey-token-issue

Conversation

@KarnaiahPesula
Copy link
Contributor

@KarnaiahPesula KarnaiahPesula commented Mar 10, 2026

Fixes: Issue# 13873 Survey token is missing while merging two cases in SORMAS
Summary:
Incorporate survey token while merging the cases.
Changes:
Introduced a new method to find the survey token for the case.
For a normal merge scenario, assign the respective caseId.
In case of cloning, it's not correct to assign the existing survey to the new case.
Updated the TestDataCreator for returning the test survey token details.
Created SurveyServiceTest to validate findSurveyToken of the case.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Case merge now reassigns survey tokens to the surviving case.
    • Service method added to retrieve survey tokens by criteria.
  • Tests

    • Added tests covering survey token creation and retrieval.
    • Test helper to create survey tokens for test data.
  • Style

    • Minor formatting/indentation cleanup.

@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

Extends case-merge logic to reassign SurveyToken entities to the lead case, adds a finder method to query SurveyToken by criteria, and introduces test helpers and a new test validating survey token creation and retrieval.

Changes

Cohort / File(s) Summary
Formatting
sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentWorkflow.java
Reflowed two enum constant argument lists to single-line formatting; no semantic change.
Survey Token Service
sormas-backend/src/main/java/de/symeda/sormas/backend/survey/SurveyTokenService.java
Added public List<SurveyToken> findBy(SurveyTokenCriteria criteria) to build and execute a criteria query, apply filters, order by assignment date desc, and return results.
Case Merge Logic
sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java
Injected SurveyTokenService and, in non-cloning merge path, reassigns existing SurveyToken entities from the merged case to the lead case and persists updates.
Test Infrastructure
sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java, sormas-backend/src/test/.../survey/SurveyServiceTest.java
Added createSurveyToken(CaseReferenceDto) helper to create/persist a SurveyToken; added SurveyServiceTest to create test data and assert token retrieval via SurveyTokenService.findBy.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant CaseFacade as CaseFacadeEjb
participant SurveySvc as SurveyTokenService
participant DB as Database
Note over CaseFacade,SurveySvc: Merge non-cloning flow reassigns tokens
CaseFacade->>SurveySvc: findBy(criteria: tokens for otherCase)
SurveySvc->>DB: query SurveyToken with criteria (order by assignmentDate DESC)
DB-->>SurveySvc: list of SurveyToken
SurveySvc-->>CaseFacade: tokens
CaseFacade->>DB: update token.caseAssignedTo = leadCase (persist)
DB-->>CaseFacade: persist confirmation

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through code with a twitchy nose,
I nudged tokens where the lead-case goes,
Merged the paths with a gentle thump,
Tests chimed in with a tiny bump,
Hooray — surveys follow where the rabbit shows! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title references bugfix 13843 and specifically addresses survey token issues during case merging, which aligns with the main changes to handle survey tokens in CaseFacadeEjb.
Description check ✅ Passed The description references issue #13873, provides a clear summary of changes, and details the modifications made (survey token handling during merges, TestDataCreator updates, and new tests).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix-13843-merging-case-survey-token-issue

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.41.0)
sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@KarnaiahPesula KarnaiahPesula removed the request for review from raulbob March 10, 2026 09:13
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
sormas-backend/src/main/java/de/symeda/sormas/backend/survey/SurveyTokenService.java (1)

112-123: Extract the shared token-query builder.

findBy now duplicates the same filter/order assembly already present in getToken. A small private helper would keep those two paths from drifting the next time the criteria or sort order changes.

🤖 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/survey/SurveyTokenService.java`
around lines 112 - 123, findBy duplicates the filter and ordering logic used in
getToken; extract a private helper (e.g., buildTokenQuery or
createTokenCriteriaQuery) that accepts SurveyTokenCriteria, CriteriaBuilder and
returns a configured CriteriaQuery/TypedQuery or Predicate+Order, reusing
buildCriteriaFilter and new SurveyTokenJoins(root) and applying
cb.desc(root.get(SurveyToken.ASSIGNMENT_DATE)); replace the duplicated code in
both findBy and getToken to call this helper so filter construction and order
are centralized.
sormas-backend/src/test/java/de/symeda/sormas/backend/survey/SurveyServiceTest.java (2)

18-21: Class name is misleading.

The class is named SurveyServiceTest but it tests SurveyTokenService.findBy() functionality. Consider renaming to SurveyTokenServiceTest to accurately reflect what is being tested.

♻️ Suggested rename
-public class SurveyServiceTest extends AbstractBeanTest {
+public class SurveyTokenServiceTest extends AbstractBeanTest {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/test/java/de/symeda/sormas/backend/survey/SurveyServiceTest.java`
around lines 18 - 21, The test class is misnamed: currently class
SurveyServiceTest but exercises SurveyTokenService.findBy(); rename the class to
SurveyTokenServiceTest (update the class declaration SurveyServiceTest ->
SurveyTokenServiceTest) and update the test file name and any references/imports
or test-suite entries that reference SurveyServiceTest so they match the new
name; ensure the test runner/annotations remain intact and run tests to verify
no remaining broken references.

33-41: Strengthen test assertions to verify actual behavior.

The current assertion only checks that the list is non-empty, which is a weak validation. The test should verify:

  1. The exact number of tokens returned (should be 1)
  2. The token is associated with the correct case
  3. The token value matches

This makes the test more reliable and catches regressions more effectively.

♻️ Proposed improvement
 	`@Test`
 	public void testSurveyTokens() {
 		CaseDataDto caze = creator.createCase(surveillanceOfficer.toReference(), rdcf, (c) -> {
 			c.setDisease(Disease.MALARIA);
 		});
-		creator.createSurveyToken(caze.toReference());
-		List<SurveyToken> tokenList = getSurveyTokenService().findBy(new SurveyTokenCriteria());
-		assertThat(tokenList.size(), is(greaterThan(0)));
+		SurveyTokenDto createdToken = creator.createSurveyToken(caze.toReference());
+		
+		SurveyTokenCriteria criteria = new SurveyTokenCriteria();
+		List<SurveyToken> tokenList = getSurveyTokenService().findBy(criteria);
+		
+		assertThat(tokenList.size(), is(1));
+		SurveyToken retrievedToken = tokenList.get(0);
+		assertThat(retrievedToken.getUuid(), is(createdToken.getUuid()));
+		assertThat(retrievedToken.getCaseAssignedTo().getUuid(), is(caze.getUuid()));
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/test/java/de/symeda/sormas/backend/survey/SurveyServiceTest.java`
around lines 33 - 41, Update the testSurveyTokens test to assert concrete
behavior: after creating a case (CaseDataDto caze) and calling
creator.createSurveyToken(caze.toReference()), query SurveyToken list via
getSurveyTokenService().findBy(new SurveyTokenCriteria()) and assert the list
size equals 1, then fetch the single SurveyToken and assert its case/reference
matches caze.toReference() and its token value is not null and equals the value
returned/created by creator.createSurveyToken (or the stored token value), using
the SurveyToken class fields to compare (e.g., getCaseReference()/getToken()) so
the test verifies number, association, and token value rather than just
non-empty list.
sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java (1)

2480-2486: Consider adding flexibility to the test helper method.

The current implementation has several limitations:

  1. Hardcoded survey name and disease ("Malaria-Survey", Disease.MALARIA) regardless of the case's actual disease
  2. Fixed token value "MALA01" may cause conflicts if called multiple times
  3. A new survey is created on every call, which may lead to unnecessary test data

Consider following the established pattern in this class by adding a Consumer<SurveyTokenDto> parameter for customization:

♻️ Proposed refactor for flexibility
-	public SurveyTokenDto createSurveyToken(CaseReferenceDto caze) {
-		SurveyDto survey = this.createSurvey("Malaria-Survey", Disease.MALARIA);
+	public SurveyTokenDto createSurveyToken(CaseReferenceDto caze, SurveyDto survey, Consumer<SurveyTokenDto> customConfig) {
 		SurveyTokenDto token = SurveyTokenDto.build(survey.toReference());
-		token.setToken("MALA01");
+		token.setToken(DataHelper.createUuid().substring(0, 8));
 		token.setCaseAssignedTo(caze);
+		if (customConfig != null) {
+			customConfig.accept(token);
+		}
 		return beanTest.getSurveyTokenFacade().save(token);
 	}
+
+	public SurveyTokenDto createSurveyToken(CaseReferenceDto caze) {
+		SurveyDto survey = this.createSurvey("Test-Survey", Disease.MALARIA);
+		return createSurveyToken(caze, survey, null);
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java`
around lines 2480 - 2486, The createSurveyToken(CaseReferenceDto caze) helper is
too rigid—change it to accept a Consumer<SurveyTokenDto> (or add an overloaded
method) so callers can customize the token; when creating the SurveyTokenDto
(currently built via SurveyTokenDto.build(survey.toReference())), derive the
survey parameters from the provided case (use the case's disease or reuse an
existing survey instead of always calling createSurvey("Malaria-Survey",
Disease.MALARIA)), generate a unique token value instead of the fixed "MALA01"
(e.g., append a timestamp or counter), apply the Consumer to allow further
tweaks, and then save via beanTest.getSurveyTokenFacade().save(token); keep the
original method as a simple wrapper to preserve tests.
🤖 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/survey/SurveyTokenService.java`:
- Around line 112-123: findBy duplicates the filter and ordering logic used in
getToken; extract a private helper (e.g., buildTokenQuery or
createTokenCriteriaQuery) that accepts SurveyTokenCriteria, CriteriaBuilder and
returns a configured CriteriaQuery/TypedQuery or Predicate+Order, reusing
buildCriteriaFilter and new SurveyTokenJoins(root) and applying
cb.desc(root.get(SurveyToken.ASSIGNMENT_DATE)); replace the duplicated code in
both findBy and getToken to call this helper so filter construction and order
are centralized.

In
`@sormas-backend/src/test/java/de/symeda/sormas/backend/survey/SurveyServiceTest.java`:
- Around line 18-21: The test class is misnamed: currently class
SurveyServiceTest but exercises SurveyTokenService.findBy(); rename the class to
SurveyTokenServiceTest (update the class declaration SurveyServiceTest ->
SurveyTokenServiceTest) and update the test file name and any references/imports
or test-suite entries that reference SurveyServiceTest so they match the new
name; ensure the test runner/annotations remain intact and run tests to verify
no remaining broken references.
- Around line 33-41: Update the testSurveyTokens test to assert concrete
behavior: after creating a case (CaseDataDto caze) and calling
creator.createSurveyToken(caze.toReference()), query SurveyToken list via
getSurveyTokenService().findBy(new SurveyTokenCriteria()) and assert the list
size equals 1, then fetch the single SurveyToken and assert its case/reference
matches caze.toReference() and its token value is not null and equals the value
returned/created by creator.createSurveyToken (or the stored token value), using
the SurveyToken class fields to compare (e.g., getCaseReference()/getToken()) so
the test verifies number, association, and token value rather than just
non-empty list.

In `@sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java`:
- Around line 2480-2486: The createSurveyToken(CaseReferenceDto caze) helper is
too rigid—change it to accept a Consumer<SurveyTokenDto> (or add an overloaded
method) so callers can customize the token; when creating the SurveyTokenDto
(currently built via SurveyTokenDto.build(survey.toReference())), derive the
survey parameters from the provided case (use the case's disease or reuse an
existing survey instead of always calling createSurvey("Malaria-Survey",
Disease.MALARIA)), generate a unique token value instead of the fixed "MALA01"
(e.g., append a timestamp or counter), apply the Consumer to allow further
tweaks, and then save via beanTest.getSurveyTokenFacade().save(token); keep the
original method as a simple wrapper to preserve tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 392dfe13-378b-414c-b200-d14a2f6e6761

📥 Commits

Reviewing files that changed from the base of the PR and between e7a0d70 and 301c6f3.

📒 Files selected for processing (5)
  • sormas-api/src/main/java/de/symeda/sormas/api/docgeneneration/DocumentWorkflow.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/survey/SurveyTokenService.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/survey/SurveyServiceTest.java

@sormas-vitagroup
Copy link
Contributor

…n SORMAS

Summary:
Incorporate survey token while merging the cases.
Changes:
Introduced a new method to find the survey token for the case.
For a normal merge scenario, assign the respective caseId.
In case of cloning, it's not correct to assign the existing survey to the new case.
Updated the TestDataCreator for returning the test survey token details.
Created SurveyServiceTest to validate findSurveyToken of the case.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java (1)

2480-2491: Incomplete Javadoc and hardcoded token value.

The Javadoc has empty @param caze and @return descriptions. Consider completing them for clarity.

The hardcoded token value "MALA01" works because the token column lacks a unique constraint (per SurveyToken.java), but this approach may cause test isolation issues if multiple tests call this method and later query tokens without filtering by the specific case or survey.

📝 Suggested Javadoc improvement
 /**
- * 
- * `@param` caze
- * `@return`
+ * Creates a survey token assigned to the given case for testing purposes.
+ * 
+ * `@param` caze the case reference to associate with the token
+ * `@return` the persisted SurveyTokenDto
  */
 public SurveyTokenDto createSurveyToken(CaseReferenceDto caze) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java`
around lines 2480 - 2491, The createSurveyToken method's Javadoc is incomplete
and the token value is hardcoded which can cause cross-test collisions; update
the Javadoc to describe the caze parameter and the returned SurveyTokenDto, and
change the token generation in createSurveyToken (rather than
token.setToken("MALA01")) to produce a unique value per call (e.g., append a
UUID or use survey/case identifiers) before saving via
beanTest.getSurveyTokenFacade().save(token); reference SurveyTokenDto.build,
token.setToken, and SurveyToken.java when making the change.
🤖 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/test/java/de/symeda/sormas/backend/survey/SurveyServiceTest.java`:
- Around line 52-65: The test has two issues: the Javadoc incorrectly references
SurveyService#findBy (update it to SurveyTokenService#findBy) and the query uses
new SurveyTokenCriteria() which returns all tokens causing flaky ordering; fix
by populating the criteria with the created case reference (use the appropriate
setter on SurveyTokenCriteria, e.g., setCaseRef(caze.toReference()) or
equivalent) before calling getSurveyTokenService().findBy so the result is
limited to the token created by creator.createSurveyToken(caze.toReference())
and update assertions accordingly.

---

Nitpick comments:
In `@sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java`:
- Around line 2480-2491: The createSurveyToken method's Javadoc is incomplete
and the token value is hardcoded which can cause cross-test collisions; update
the Javadoc to describe the caze parameter and the returned SurveyTokenDto, and
change the token generation in createSurveyToken (rather than
token.setToken("MALA01")) to produce a unique value per call (e.g., append a
UUID or use survey/case identifiers) before saving via
beanTest.getSurveyTokenFacade().save(token); reference SurveyTokenDto.build,
token.setToken, and SurveyToken.java when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f9bea33e-ca4f-4ffd-9e50-e1dd134d35c8

📥 Commits

Reviewing files that changed from the base of the PR and between 301c6f3 and 3d6a3e1.

📒 Files selected for processing (3)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/TestDataCreator.java
  • sormas-backend/src/test/java/de/symeda/sormas/backend/survey/SurveyServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java

Comment on lines +52 to +65
/**
* Test method for {@link de.symeda.sormas.backend.survey.SurveyService#findBy(de.symeda.sormas.api.survey.SurveyTokenCriteria)}.
*
*/
@Test
public void testSurveyTokens() {
CaseDataDto caze = creator.createCase(surveillanceOfficer.toReference(), rdcf, (c) -> {
c.setDisease(Disease.MALARIA);
});
creator.createSurveyToken(caze.toReference());
List<SurveyToken> tokenList = getSurveyTokenService().findBy(new SurveyTokenCriteria());
assertThat(tokenList.size(), is(greaterThan(0)));
assertThat(tokenList.get(0).getToken(), is(equalTo("MALA01")));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Test may be flaky due to unfiltered query and incorrect Javadoc reference.

  1. Incorrect Javadoc: Line 53 references SurveyService#findBy but the actual method being tested is SurveyTokenService#findBy.

  2. Test isolation concern: Using new SurveyTokenCriteria() returns ALL survey tokens in the database (per SurveyTokenService.buildCriteriaFilter which returns null when all criteria fields are null). If other tests in the suite create tokens, this test could:

    • Pass assertion at Line 63 (size > 0) but for the wrong reason
    • Fail assertion at Line 64 if another token with a newer ASSIGNMENT_DATE appears first

Consider filtering by the created case or survey to ensure test isolation:

🛡️ Suggested fix for test isolation
 /**
- * Test method for {`@link` de.symeda.sormas.backend.survey.SurveyService#findBy(de.symeda.sormas.api.survey.SurveyTokenCriteria)}.
+ * Test method for {`@link` de.symeda.sormas.backend.survey.SurveyTokenService#findBy(de.symeda.sormas.api.survey.SurveyTokenCriteria)}.
  * 
  */
 `@Test`
 public void testSurveyTokens() {
 	CaseDataDto caze = creator.createCase(surveillanceOfficer.toReference(), rdcf, (c) -> {
 		c.setDisease(Disease.MALARIA);
 	});
-	creator.createSurveyToken(caze.toReference());
-	List<SurveyToken> tokenList = getSurveyTokenService().findBy(new SurveyTokenCriteria());
+	SurveyTokenDto createdToken = creator.createSurveyToken(caze.toReference());
+	SurveyTokenCriteria criteria = new SurveyTokenCriteria();
+	criteria.setCaseAssignedTo(caze.toReference());
+	List<SurveyToken> tokenList = getSurveyTokenService().findBy(criteria);
 	assertThat(tokenList.size(), is(greaterThan(0)));
 	assertThat(tokenList.get(0).getToken(), is(equalTo("MALA01")));
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/test/java/de/symeda/sormas/backend/survey/SurveyServiceTest.java`
around lines 52 - 65, The test has two issues: the Javadoc incorrectly
references SurveyService#findBy (update it to SurveyTokenService#findBy) and the
query uses new SurveyTokenCriteria() which returns all tokens causing flaky
ordering; fix by populating the criteria with the created case reference (use
the appropriate setter on SurveyTokenCriteria, e.g.,
setCaseRef(caze.toReference()) or equivalent) before calling
getSurveyTokenService().findBy so the result is limited to the token created by
creator.createSurveyToken(caze.toReference()) and update assertions accordingly.

@sormas-vitagroup
Copy link
Contributor

@sormas-vitagroup
Copy link
Contributor

@KarnaiahPesula KarnaiahPesula requested a review from raulbob March 10, 2026 15:59
@KarnaiahPesula KarnaiahPesula merged commit 5a262f6 into development Mar 11, 2026
7 of 13 checks passed
@KarnaiahPesula KarnaiahPesula deleted the bugfix-13843-merging-case-survey-token-issue branch March 11, 2026 08:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When merging two cases, if one case has an assigned survey token, the merge does not include this information

3 participants