diff --git a/src/main/java/com/iemr/flw/controller/DynamicFormController.java b/src/main/java/com/iemr/flw/controller/DynamicFormController.java index 59295cbf..254313e9 100644 --- a/src/main/java/com/iemr/flw/controller/DynamicFormController.java +++ b/src/main/java/com/iemr/flw/controller/DynamicFormController.java @@ -22,6 +22,7 @@ package com.iemr.flw.controller; import com.iemr.flw.dto.iemr.DynamicFormDTO; +import com.iemr.flw.dto.iemr.LatestFormVersionDTO; import com.iemr.flw.service.DynamicFormDefinitionService; import com.iemr.flw.utils.ApiResponse; import io.swagger.v3.oas.annotations.Operation; @@ -35,6 +36,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** * REST controller for dynamic form definition management. * All write operations use POST; all read operations use GET. @@ -97,4 +100,10 @@ public ResponseEntity deactivateForm( return ResponseEntity.ok(new ApiResponse(true, "Form deactivated", null)); } + @Operation(summary = "Get the latest version of each active form (formId, formUuid, formName, currentVersionNumber)") + @RequestMapping(value = "/getLatestFormVersions", method = RequestMethod.GET) + public ResponseEntity getLatestFormVersions() { + List result = formService.getLatestFormVersions(); + return ResponseEntity.ok(new ApiResponse(true, "Latest form versions fetched successfully", result)); + } } diff --git a/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java index 645fa0d1..9a35f1a8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java @@ -21,6 +21,7 @@ */ package com.iemr.flw.domain.iemr; +import com.iemr.flw.masterEnum.FormType; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -70,6 +71,10 @@ public class QuestionOption { @Column(name = "optionValue", nullable = false, length = 100) private String optionValue; + /** Stable across every version of a form (formType + optionValue), unlike optionId — see {@link #buildOptionUuid}. */ + @Column(name = "optionUuid", length = 255) + private String optionUuid; + @Column(name = "optionValue_hindi", length = 100) private String optionValueHindi; @@ -111,4 +116,12 @@ public class QuestionOption { @Column(name = "SyncFailureReason") private String syncFailureReason; + + /** e.g. (OCCUPATION_CONTACT_TRACING, "Yes") → "OCCUPATION_CONTACT_TRACING_YES". */ + public static String buildOptionUuid(FormType formType, String optionValue) { + String normalized = optionValue.toUpperCase() + .replaceAll("[^A-Z0-9]+", "_") + .replaceAll("^_+|_+$", ""); + return formType.name() + "_" + normalized; + } } diff --git a/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java index d53a5823..8ab1e390 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java @@ -44,6 +44,8 @@ public class FormResponseDTO { private Long beneficiaryId; private Long formId; private Long versionId; + /** Version number of the form version this response was captured against (versionId), not necessarily the latest. */ + private Integer versionNumber; private Long officerId; private String status; private String createdBy; diff --git a/src/main/java/com/iemr/flw/dto/iemr/LatestFormVersionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/LatestFormVersionDTO.java new file mode 100644 index 00000000..ee1d197e --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/LatestFormVersionDTO.java @@ -0,0 +1,42 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Latest version summary of a dynamic form: identifies the form and its current version number. + * + * @author Piramal Swasthya + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class LatestFormVersionDTO { + private Long formId; + private String formUuid; + private String formName; + private Long versionId; + private Integer currentVersionNumber; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java index 6682404a..4831f957 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java @@ -51,6 +51,9 @@ public class QuestionOptionDTO { private String optionValueHindi; + /** Optional on input — derived from formType + optionValue when blank. */ + private String optionUuid; + @NotNull(message = "displayOrder is required") private Integer displayOrder; diff --git a/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java index 03f1622e..f3ec7b39 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java @@ -40,8 +40,13 @@ public class QuestionResponseDTO { private Long questionResponseId; private Long questionId; + private String questionUuid; /** Populated for RADIO, DROPDOWN, MCQ, CHECKBOX, CHECKBOX_MULTI, and DROPDOWN_MULTI answers. */ private Long optionId; + /** optionValue of the selected option; null when optionId is null. */ + private String optionValue; + /** Stable across form versions; null when optionId is null. */ + private String optionUuid; /** Populated for TEXT, DATE, AUTO_FILL, NUMBER_PICKER answers. */ private String answerText; } diff --git a/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java index f389b5de..c2abe9a0 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java @@ -41,6 +41,8 @@ public interface FormResponseRepo extends JpaRepository { List findByBeneficiaryIdAndFormId(Long beneficiaryId, Long formId); + List findByBeneficiaryIdAndVersionId(Long beneficiaryId, Long versionId); + @Query("SELECT r FROM FormResponse r WHERE r.formId = :formId AND r.status IN :statuses") List findByFormIdAndStatusIn(@Param("formId") Long formId, @Param("statuses") List statuses); diff --git a/src/main/java/com/iemr/flw/repo/iemr/FormVersionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FormVersionRepo.java index 1d8583ae..e7a8c8ec 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/FormVersionRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/FormVersionRepo.java @@ -22,7 +22,9 @@ package com.iemr.flw.repo.iemr; import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.dto.iemr.LatestFormVersionDTO; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; @@ -43,4 +45,10 @@ public interface FormVersionRepo extends JpaRepository { List findByDynamicForm_FormIdOrderByVersionNumberAsc(Long formId); Optional findByDynamicForm_FormUuidAndIsLatest(String formUuid, boolean b); + + @Query("SELECT new com.iemr.flw.dto.iemr.LatestFormVersionDTO(f.formId, f.formUuid, f.formName, v.versionId, v.versionNumber) " + + "FROM FormVersion v JOIN v.dynamicForm f " + + "WHERE v.isLatest = true AND f.isActive = true " + + "ORDER BY f.formId ASC") + List findLatestVersionOfActiveForms(); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java index 0d8e8796..7b5b3418 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java @@ -60,4 +60,10 @@ void shiftDisplayOrder(@Param("questionId") Long questionId, @Param("from") int @Query("SELECT o FROM QuestionOption o JOIN FETCH o.sectionQuestion " + "WHERE o.sectionQuestion.questionId IN :questionIds AND o.isActive = true ORDER BY o.displayOrder ASC") List findByQuestionIdsOrderByDisplayOrderAsc(@Param("questionIds") Collection questionIds); + + /** All options (every form, every version, inactive included) still missing an optionUuid — used by the V009 backfill. */ + @Query("SELECT o FROM QuestionOption o JOIN FETCH o.sectionQuestion q JOIN FETCH q.formSection s " + + "JOIN FETCH s.formVersion v JOIN FETCH v.dynamicForm " + + "WHERE o.optionUuid IS NULL OR o.optionUuid = ''") + List findAllMissingOptionUuid(); } diff --git a/src/main/java/com/iemr/flw/seeder/migration/V009_BackfillOptionUuid.java b/src/main/java/com/iemr/flw/seeder/migration/V009_BackfillOptionUuid.java new file mode 100644 index 00000000..bfcb384d --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/migration/V009_BackfillOptionUuid.java @@ -0,0 +1,62 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.seeder.migration; + +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.repo.iemr.QuestionOptionRepo; +import com.iemr.flw.service.DynamicFormReconciliationService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Backfills t_question_option.optionUuid for every option of every form version created before + * the column existed. The uuid is formType + optionValue, so the same option resolves to the same + * optionUuid in v1, v2, … — letting clients map answers across versions, as with sectionUuid/questionUuid. + * Only touches rows whose optionUuid is still blank, so re-running is a no-op. + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class V009_BackfillOptionUuid implements FormStructureMigration { + + private final QuestionOptionRepo optionRepo; + + @Override + public String migrationId() { + return "V009"; + } + + @Override + public void apply(DynamicFormReconciliationService svc) { + List options = optionRepo.findAllMissingOptionUuid(); + for (QuestionOption option : options) { + option.setOptionUuid(QuestionOption.buildOptionUuid( + option.getSectionQuestion().getFormSection().getFormVersion().getDynamicForm().getFormType(), + option.getOptionValue())); + } + optionRepo.saveAll(options); + log.info("V009: backfilled optionUuid on {} option(s).", options.size()); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java b/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java index ed2d92d5..b3e5558c 100644 --- a/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java +++ b/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java @@ -23,6 +23,7 @@ import com.iemr.flw.dto.iemr.DynamicFormDTO; import com.iemr.flw.dto.iemr.FormSectionDTO; +import com.iemr.flw.dto.iemr.LatestFormVersionDTO; import com.iemr.flw.dto.iemr.OptionConditionDTO; import com.iemr.flw.dto.iemr.QuestionOptionDTO; import com.iemr.flw.dto.iemr.QuestionValidationDTO; @@ -56,4 +57,6 @@ public interface DynamicFormDefinitionService { /** Sets the form's isActive flag to false and invalidates cache. */ void deactivateForm(Long formId); + /** Latest version of every active form: formId, formUuid, formName and current version number. */ + List getLatestFormVersions(); } diff --git a/src/main/java/com/iemr/flw/service/impl/DynamicFormDefinitionServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DynamicFormDefinitionServiceImpl.java index e61bc5c0..1df9a201 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormDefinitionServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormDefinitionServiceImpl.java @@ -30,6 +30,7 @@ import com.iemr.flw.domain.iemr.SectionQuestion; import com.iemr.flw.dto.iemr.DynamicFormDTO; import com.iemr.flw.dto.iemr.FormSectionDTO; +import com.iemr.flw.dto.iemr.LatestFormVersionDTO; import com.iemr.flw.dto.iemr.OptionConditionDTO; import com.iemr.flw.dto.iemr.QuestionOptionDTO; import com.iemr.flw.dto.iemr.QuestionValidationDTO; @@ -213,6 +214,10 @@ private void buildSectionsFromDto(List dtos, FormVersion version for (QuestionOptionDTO oDto : qDto.getOptions()) { QuestionOption opt = mapper.toEntity(oDto); opt.setSectionQuestion(savedQ); + if (opt.getOptionUuid() == null || opt.getOptionUuid().isBlank()) { + opt.setOptionUuid(QuestionOption.buildOptionUuid( + version.getDynamicForm().getFormType(), opt.getOptionValue())); + } opt.setConditions(new ArrayList<>()); QuestionOption savedOpt = optionRepo.save(opt); if (oDto.getConditions() != null && !oDto.getConditions().isEmpty()) { @@ -423,4 +428,9 @@ private SectionQuestion requireQuestion(Long questionId) { .orElseThrow(() -> new RuntimeException("Question not found: " + questionId)); } + @Override + @Transactional(readOnly = true) + public List getLatestFormVersions() { + return versionRepo.findLatestVersionOfActiveForms(); + } } diff --git a/src/main/java/com/iemr/flw/service/impl/DynamicFormReconciliationServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DynamicFormReconciliationServiceImpl.java index d5de312b..235093d4 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormReconciliationServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormReconciliationServiceImpl.java @@ -253,6 +253,11 @@ private QuestionOption createOption(SectionQuestion question, QuestionOptionDTO QuestionOption option = mapper.toEntity(dto); option.setOptionId(null); option.setSectionQuestion(question); + if (option.getOptionUuid() == null || option.getOptionUuid().isBlank()) { + option.setOptionUuid(QuestionOption.buildOptionUuid( + question.getFormSection().getFormVersion().getDynamicForm().getFormType(), + option.getOptionValue())); + } option.setDisplayOrder(order); option.setConditions(new ArrayList<>()); return optionRepo.save(option); diff --git a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java index e163959c..f74088a6 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java @@ -64,6 +64,7 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -136,7 +137,7 @@ public FormResponseDTO completeForm(FormResponseRequest request, String jwtToken Timestamp now = new Timestamp(System.currentTimeMillis()); List existing = - formResponseRepo.findByBeneficiaryIdAndFormId(request.getBeneficiaryId(), formId); + formResponseRepo.findByBeneficiaryIdAndVersionId(request.getBeneficiaryId(), version.getVersionId()); FormResponse formResponse = existing.isEmpty() ? createFormResponse(request, version, FormResponseStatus.SUBMITTED.name(), now, vanID, parkingPlaceID) : existing.get(0); @@ -164,8 +165,21 @@ public List getResponsesByBeneficiary(Long beneficiaryId, Integ List responses = beneficiaryId != null ? formResponseRepo.findByBeneficiaryIdAndFormId(beneficiaryId, formId) : formResponseRepo.findByFormIdFiltered(formId, villageId, providerServiceMapId); + + // Responses may belong to older versions than the latest one resolved above. + Set versionIds = responses.stream() + .map(FormResponse::getVersionId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Map versionNumberById = formVersionRepo.findAllById(versionIds).stream() + .collect(Collectors.toMap(FormVersion::getVersionId, FormVersion::getVersionNumber)); + return responses.stream() - .map(r -> buildFormResponseDTO(r, loadSectionResponseDTOs(r.getResponseId()))) + .map(r -> { + FormResponseDTO dto = buildFormResponseDTO(r, loadSectionResponseDTOs(r.getResponseId())); + dto.setVersionNumber(versionNumberById.get(r.getVersionId())); + return dto; + }) .collect(Collectors.toList()); } @@ -244,8 +258,12 @@ private FormResponseDTO processSections( Set questionIds = allQuestions.stream() .map(SectionQuestion::getQuestionId) .collect(Collectors.toSet()); + Map questionUuidById = allQuestions.stream() + .collect(Collectors.toMap(SectionQuestion::getQuestionId, SectionQuestion::getQuestionUuid)); List allOptions = questionOptionRepo.findByQuestionIdsOrderByDisplayOrderAsc(questionIds); + Map optionById = allOptions.stream() + .collect(Collectors.toMap(QuestionOption::getOptionId, Function.identity())); // Map: questionId → (optionValue → QuestionOption) Map> optionsByQuestion = allOptions.stream() @@ -299,7 +317,7 @@ private FormResponseDTO processSections( questionResponseRepo.updateVanSerialNo(qr.getQuestionResponseId(), qr.getQuestionResponseId()); } - sectionDTOs.add(buildSectionResponseDTO(sectionResponse, section, questionResponses)); + sectionDTOs.add(buildSectionResponseDTO(sectionResponse, section, questionResponses, questionUuidById, optionById)); } return buildFormResponseDTO(formResponse, sectionDTOs); @@ -461,11 +479,26 @@ private List loadSectionResponseDTOs(Long responseId) { Map sectionById = formSectionRepo.findAllById(sectionIds).stream() .collect(Collectors.toMap(FormSection::getSectionId, Function.identity())); + // findAllById includes unlinked (isActive=false) questions, so historical answers still resolve their uuid. + Set questionIds = allAnswers.stream() + .map(QuestionResponse::getQuestionId) + .collect(Collectors.toSet()); + Map questionUuidById = sectionQuestionRepo.findAllById(questionIds).stream() + .collect(Collectors.toMap(SectionQuestion::getQuestionId, SectionQuestion::getQuestionUuid)); + Set optionIds = allAnswers.stream() + .map(QuestionResponse::getOptionId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Map optionById = questionOptionRepo.findAllById(optionIds).stream() + .collect(Collectors.toMap(QuestionOption::getOptionId, Function.identity())); + return sections.stream() .map(sr -> buildSectionResponseDTO( sr, sectionById.get(sr.getSectionId()), - answersBySectionResponse.getOrDefault(sr.getSectionResponseId(), List.of()))) + answersBySectionResponse.getOrDefault(sr.getSectionResponseId(), List.of()), + questionUuidById, + optionById)) .collect(Collectors.toList()); } @@ -489,12 +522,18 @@ private FormResponseDTO buildFormResponseDTO(FormResponse r, List answers) { + SectionResponse sr, FormSection section, List answers, + Map questionUuidById, Map optionById) { List answerDTOs = answers.stream() .map(a -> QuestionResponseDTO.builder() .questionResponseId(a.getQuestionResponseId()) .questionId(a.getQuestionId()) + .questionUuid(questionUuidById.get(a.getQuestionId())) .optionId(a.getOptionId()) + .optionValue(optionById.containsKey(a.getOptionId()) + ? optionById.get(a.getOptionId()).getOptionValue() : null) + .optionUuid(optionById.containsKey(a.getOptionId()) + ? optionById.get(a.getOptionId()).getOptionUuid() : null) .answerText(a.getAnswerText()) .build()) .collect(Collectors.toList()); diff --git a/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java b/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java index f03398c5..9a6e0487 100644 --- a/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java +++ b/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java @@ -112,7 +112,7 @@ public FormResponseDTO saveForBulk(FormResponseRequest req, String jwtToken) thr // Step 2: Check for an existing response for this beneficiary+form List existing = - formResponseRepo.findByBeneficiaryIdAndFormId(req.getBeneficiaryId(), formId); + formResponseRepo.findByBeneficiaryIdAndVersionId(req.getBeneficiaryId(), version.getVersionId()); FormResponse formResponse; if (!existing.isEmpty()) { @@ -221,8 +221,12 @@ private FormResponseDTO processSections(FormResponse formResponse, FormResponseR Set questionIds = allQuestions.stream() .map(SectionQuestion::getQuestionId) .collect(Collectors.toSet()); + Map questionUuidById = allQuestions.stream() + .collect(Collectors.toMap(SectionQuestion::getQuestionId, SectionQuestion::getQuestionUuid)); List allOptions = questionOptionRepo.findByQuestionIdsOrderByDisplayOrderAsc(questionIds); + Map optionById = allOptions.stream() + .collect(Collectors.toMap(QuestionOption::getOptionId, Function.identity())); Map> optionsByQuestion = allOptions.stream() .collect(Collectors.groupingBy( o -> o.getSectionQuestion().getQuestionId(), @@ -271,7 +275,7 @@ private FormResponseDTO processSections(FormResponse formResponse, FormResponseR for (QuestionResponse qr : questionResponses) { questionResponseRepo.updateVanSerialNo(qr.getQuestionResponseId(), qr.getQuestionResponseId()); } - sectionDTOs.add(buildSectionResponseDTO(sectionResponse, section, questionResponses)); + sectionDTOs.add(buildSectionResponseDTO(sectionResponse, section, questionResponses, questionUuidById, optionById)); } return buildFormResponseDTO(formResponse, sectionDTOs); @@ -425,12 +429,18 @@ private FormResponseDTO buildFormResponseDTO(FormResponse r, List answers) { + SectionResponse sr, FormSection section, List answers, + Map questionUuidById, Map optionById) { List answerDTOs = answers.stream() .map(a -> QuestionResponseDTO.builder() .questionResponseId(a.getQuestionResponseId()) .questionId(a.getQuestionId()) + .questionUuid(questionUuidById.get(a.getQuestionId())) .optionId(a.getOptionId()) + .optionValue(optionById.containsKey(a.getOptionId()) + ? optionById.get(a.getOptionId()).getOptionValue() : null) + .optionUuid(optionById.containsKey(a.getOptionId()) + ? optionById.get(a.getOptionId()).getOptionUuid() : null) .answerText(a.getAnswerText()) .build()) .collect(Collectors.toList());