From 341a34f252bc78d28e2fd1dfbb2618d984dc9d56 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Mon, 22 Jun 2026 12:20:53 +0530 Subject: [PATCH 01/15] Enforced mandatory validation for "Reason for Refusal in section e in file TbCounsellingFormSeeder --- src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java index d3a2c83e..6c0a248c 100644 --- a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java +++ b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java @@ -185,7 +185,7 @@ private FormSectionDTO buildSectionE() { qs.add(statusQ); // Reason for refusal — hidden by default, max 300 chars - qs.add(textQuestion("TB_E_REFUSAL", "Reason for refusal", 2, false, 300, false)); + qs.add(textQuestion("TB_E_REFUSAL", "Reason for refusal", 2, true, 300, false)); // Counsellor remarks — optional, max 500 chars qs.add(textQuestion("TB_E_REMARKS", "Counsellor remarks", 3, false, 500, true)); From 2908c20f8cbe7a0e3d59149a1ca5cc8746dedc08 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Tue, 23 Jun 2026 08:53:41 +0530 Subject: [PATCH 02/15] Added counselled flag to confirmed cases response, indicating whether a beneficiary has completed the TB Counselling form. Implemented using a single bulk query to avoid N+1 lookups against FormResponse. --- .../DynamicFormResponseController.java | 6 ++- .../flw/domain/iemr/TBConfirmedCaseDTO.java | 1 + .../iemr/flw/repo/iemr/FormResponseRepo.java | 8 ++++ .../service/DynamicFormResponseService.java | 3 +- .../impl/DynamicFormResponseServiceImpl.java | 40 ++++++++++++------- .../service/impl/FormResponseItemSaver.java | 20 +++++----- .../impl/TBConfirmedCaseServiceImpl.java | 33 ++++++++++++--- 7 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java index 636c6bcf..78a3dd83 100644 --- a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java +++ b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java @@ -25,6 +25,7 @@ import com.iemr.flw.dto.iemr.FormResponseRequest; import com.iemr.flw.service.DynamicFormResponseService; import com.iemr.flw.utils.ApiResponse; +import com.iemr.flw.utils.exception.IEMRException; import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -64,8 +65,9 @@ public ResponseEntity submitForm( @RequestMapping(value = "/complete", method = RequestMethod.POST) public ResponseEntity completeForm( @RequestParam Long responseId, - @Valid @RequestBody FormResponseRequest request) { - FormResponseDTO dto = responseService.completeForm(responseId, request); + @Valid @RequestBody FormResponseRequest request, + @RequestHeader("JwtToken") String jwtToken) throws IEMRException { + FormResponseDTO dto = responseService.completeForm(responseId, request, jwtToken); return ResponseEntity.ok(new ApiResponse(true, "Form completed successfully", dto)); } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java index 07903035..7a521177 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java @@ -29,5 +29,6 @@ public class TBConfirmedCaseDTO { private String placeOfDeath; private String reasonForDeath ; private String reasonForNotCompleting; + private Boolean counselled; } 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 b3c1d22f..830cad08 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java @@ -42,6 +42,14 @@ public interface FormResponseRepo extends JpaRepository { List findByBeneficiaryId(Long beneficiaryId); + @Query("SELECT r.beneficiaryId FROM FormResponse r " + + "WHERE r.beneficiaryId IN :benIds " + + "AND r.formId = :formId " + + "AND r.status = :status") + List findCounselledBenIds(@Param("benIds") List benIds, + @Param("formId") Long formId, + @Param("status") String status); + @Query("SELECT r FROM FormResponse r " + "WHERE r.formId IN :formIds " + "AND r.status = 'SUBMITTED' " diff --git a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java index 9e92f98e..7a07f23f 100644 --- a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java +++ b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java @@ -23,6 +23,7 @@ import com.iemr.flw.dto.iemr.FormResponseDTO; import com.iemr.flw.dto.iemr.FormResponseRequest; +import com.iemr.flw.utils.exception.IEMRException; import java.util.List; @@ -37,7 +38,7 @@ public interface DynamicFormResponseService { FormResponseDTO submitForm(FormResponseRequest request); /** Save POST_SUBMIT section answers and advance status to COMPLETE. */ - FormResponseDTO completeForm(Long responseId, FormResponseRequest request); + FormResponseDTO completeForm(Long responseId, FormResponseRequest request, String jwtToken) throws IEMRException; /** All responses for a beneficiary filtered by form UUID. */ List getResponsesByBeneficiary(Long beneficiaryId, String formUuid); 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 c3649990..4d1df037 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java @@ -43,6 +43,8 @@ import com.iemr.flw.repo.iemr.SectionResponseRepo; import com.iemr.flw.masterEnum.QuestionType; import com.iemr.flw.service.DynamicFormResponseService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -83,6 +85,7 @@ public class DynamicFormResponseServiceImpl implements DynamicFormResponseServic private final SectionQuestionRepo sectionQuestionRepo; private final QuestionOptionRepo questionOptionRepo; private final FormResponseItemSaver itemSaver; + private final JwtUtil jwtUtil; @Override @Transactional @@ -107,18 +110,20 @@ public FormResponseDTO submitForm(FormResponseRequest request) { } else { formResponse = createFormResponse(request, version, STATUS_SUBMITTED, now); } - return processSections(formResponse, request, version); + return processSections(formResponse, request, version, null); } @Override @Transactional - public FormResponseDTO completeForm(Long responseId, FormResponseRequest request) { + public FormResponseDTO completeForm(Long responseId, FormResponseRequest request, String jwtToken) throws IEMRException { + String actor = jwtUtil.extractUserId(jwtToken).toString(); FormResponse formResponse = formResponseRepo.findById(responseId) .orElseThrow(() -> new NoSuchElementException("FormResponse not found: " + responseId)); if (!STATUS_SUBMITTED.equals(formResponse.getStatus())) { throw new IllegalStateException( "Cannot complete a response in status: " + formResponse.getStatus()); } + formResponse.setUpdatedBy(actor); formResponse.setStatus(STATUS_COMPLETE); formResponse.setCompletedAt(new Timestamp(System.currentTimeMillis())); formResponse = formResponseRepo.save(formResponse); @@ -127,7 +132,7 @@ public FormResponseDTO completeForm(Long responseId, FormResponseRequest request FormVersion version = formVersionRepo.findById(formResponse.getVersionId()) .orElseThrow(() -> new NoSuchElementException( "FormVersion not found: " + finalFormResponse.getVersionId())); - return processSections(formResponse, request, version); + return processSections(formResponse, request, version, actor); } @Override @@ -187,7 +192,8 @@ private FormResponse createFormResponse( private FormResponseDTO processSections( FormResponse formResponse, FormResponseRequest request, - FormVersion version) { + FormVersion version, + String actor) { List allSections = formSectionRepo.findByFormVersion_VersionIdOrderByDisplayOrderAsc(version.getVersionId()); @@ -231,7 +237,7 @@ private FormResponseDTO processSections( } SectionResponse sectionResponse = upsertSectionResponse( - formResponse.getResponseId(), section.getSectionId()); + formResponse.getResponseId(), section.getSectionId(), actor); if ("POST_SUBMIT".equals(section.getSectionPhase())) { formResponse.setLastFollowUpAt(sectionResponse.getSavedAt()); @@ -245,7 +251,8 @@ private FormResponseDTO processSections( sectionResponse.getSectionResponseId(), sectionReq.getAnswers(), questionMap, - optionsByQuestion); + optionsByQuestion, + actor); questionResponseRepo.saveAll(questionResponses); @@ -255,13 +262,14 @@ private FormResponseDTO processSections( return buildFormResponseDTO(formResponse, sectionDTOs); } - private SectionResponse upsertSectionResponse(Long responseId, Long sectionId) { + private SectionResponse upsertSectionResponse(Long responseId, Long sectionId, String actor) { Optional existing = sectionResponseRepo.findByResponseIdAndSectionId(responseId, sectionId); if (existing.isPresent()) { SectionResponse sr = existing.get(); sr.setStatus(SECTION_STATUS_DONE); sr.setSavedAt(new Timestamp(System.currentTimeMillis())); + sr.setUpdatedBy(actor); return sectionResponseRepo.save(sr); } SectionResponse sr = SectionResponse.builder() @@ -269,9 +277,8 @@ private SectionResponse upsertSectionResponse(Long responseId, Long sectionId) { .sectionId(sectionId) .status(SECTION_STATUS_DONE) .savedAt(new Timestamp(System.currentTimeMillis())) - // TODO: set audit fields when auth is re-enabled for /dynamicForm/response endpoints - // .createdBy(jwtUtil.extractUsername(authorization)) - // .updatedBy(jwtUtil.extractUsername(authorization)) + .createdBy(actor) + .updatedBy(actor) .build(); return sectionResponseRepo.save(sr); } @@ -280,7 +287,8 @@ private List processAnswers( Long sectionResponseId, List answers, Map questionMap, - Map> optionsByQuestion) { + Map> optionsByQuestion, + String actor) { List results = new ArrayList<>(); @@ -305,10 +313,6 @@ private List processAnswers( // Delete any existing answers for this question in this section (handles re-saves) questionResponseRepo.deleteByQuestionIdAndSectionResponseId(questionId, sectionResponseId); - // TODO: set .createdBy / .updatedBy on all QuestionResponse builders below - // when auth is re-enabled for /dynamicForm/response endpoints: - // .createdBy(jwtUtil.extractUsername(authorization)) - // .updatedBy(jwtUtil.extractUsername(authorization)) if (type == QuestionType.RADIO) { if (answer.getOptionValue() != null) { QuestionOption opt = resolveOption( @@ -317,6 +321,8 @@ private List processAnswers( .sectionResponseId(sectionResponseId) .questionId(questionId) .optionId(opt != null ? opt.getOptionId() : null) + .createdBy(actor) + .updatedBy(actor) .build()); } } else if (type == QuestionType.MCQ) { @@ -328,6 +334,8 @@ private List processAnswers( .sectionResponseId(sectionResponseId) .questionId(questionId) .optionId(opt != null ? opt.getOptionId() : null) + .createdBy(actor) + .updatedBy(actor) .build()); } } @@ -340,6 +348,8 @@ private List processAnswers( .sectionResponseId(sectionResponseId) .questionId(questionId) .answerText(value) + .createdBy(actor) + .updatedBy(actor) .build()); } } 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 08cb34ae..0d844eb7 100644 --- a/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java +++ b/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java @@ -108,17 +108,7 @@ public FormResponseDTO saveForBulk(FormResponseRequest req, String jwtToken) thr formResponse = existing.get(0); Long responseId = formResponse.getResponseId(); - // Step 3: Delete old answers — children first, then parents - List oldSections = sectionResponseRepo.findByResponseId(responseId); - if (!oldSections.isEmpty()) { - Set oldSrIds = oldSections.stream() - .map(SectionResponse::getSectionResponseId) - .collect(Collectors.toSet()); - questionResponseRepo.deleteBySectionResponseIdIn(oldSrIds); - sectionResponseRepo.deleteByResponseId(responseId); - } - - // Step 4: Update FormResponse header + // Step 3: Update FormResponse header formResponse.setStatus(STATUS_SUBMITTED); formResponse.setSubmittedAt(now); formResponse.setUpdatedBy(actor); @@ -234,6 +224,14 @@ private FormResponseDTO processSections(FormResponse formResponse, FormResponseR "' not found in form '" + req.getFormUuid() + "'"); } + // Delete existing SectionResponse (and its QuestionResponses) for this section only + sectionResponseRepo.findByResponseIdAndSectionId( + formResponse.getResponseId(), section.getSectionId()) + .ifPresent(sr -> { + questionResponseRepo.deleteBySectionResponseIdIn(Set.of(sr.getSectionResponseId())); + sectionResponseRepo.deleteById(sr.getSectionResponseId()); + }); + SectionResponse sectionResponse = upsertSectionResponse( formResponse.getResponseId(), section.getSectionId(), actor); diff --git a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java index 0bf48e62..94784d29 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -2,16 +2,17 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.iemr.flw.domain.iemr.DynamicForm; import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; import com.iemr.flw.domain.iemr.TBConfirmedCase; import com.iemr.flw.domain.iemr.TBStopVisit; -import com.iemr.flw.dto.iemr.TBConfirmedCasesResponseDTO; +import com.iemr.flw.repo.iemr.DynamicFormRepo; +import com.iemr.flw.repo.iemr.FormResponseRepo; import com.iemr.flw.repo.iemr.TBConfirmedTreatmentRepository; +import com.iemr.flw.seeder.TbCounsellingFormSeeder; import com.iemr.flw.service.CampConfigService; import com.iemr.flw.service.TBConfirmedCaseService; import com.iemr.flw.service.TBStopVisitService; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.iemr.flw.utils.JwtUtil; import com.iemr.flw.utils.LocalDateAdapter; import com.iemr.flw.utils.response.OutputResponse; @@ -21,9 +22,12 @@ import org.springframework.stereotype.Service; import java.time.LocalDate; -import java.util.HashMap; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; @Service @@ -32,6 +36,8 @@ public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { private static final Logger logger = LoggerFactory.getLogger(TBConfirmedCaseServiceImpl.class); private final TBConfirmedTreatmentRepository repository; + private final FormResponseRepo formResponseRepo; + private final DynamicFormRepo dynamicFormRepo; @Autowired private JwtUtil jwtUtil; @@ -41,8 +47,13 @@ public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { @Autowired private TBStopVisitService tbStopVisitService; - public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository) { + + public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository, + FormResponseRepo formResponseRepo, + DynamicFormRepo dynamicFormRepo) { this.repository = repository; + this.formResponseRepo = formResponseRepo; + this.dynamicFormRepo = dynamicFormRepo; } @Override @@ -135,6 +146,18 @@ public String getByUserId(String authorisation) throws Exception { Integer userId = jwtUtil.extractUserId(authorisation); List list = repository.findByUserId(userId); List dtoList = list.stream().map(this::toDTO).collect(Collectors.toList()); + + List benIds = dtoList.stream().map(TBConfirmedCaseDTO::getBenId).collect(Collectors.toList()); + Set counselledBenIds = Collections.emptySet(); + if (!benIds.isEmpty()) { + Optional counsellingForm = dynamicFormRepo.findByFormUuid(TbCounsellingFormSeeder.FORM_UUID); + if (counsellingForm.isPresent()) { + counselledBenIds = new HashSet<>(formResponseRepo.findCounselledBenIds(benIds, counsellingForm.get().getFormId(), "COMPLETE")); + } + } + final Set counselled = counselledBenIds; + dtoList.forEach(dto -> dto.setCounselled(counselled.contains(dto.getBenId()))); + Map response = new java.util.HashMap<>(); response.put("userId", userId); response.put("tbConfirmedCases", dtoList); From 939690554eea878e467dcabc7a7ca66e52d497f4 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Tue, 23 Jun 2026 11:07:19 +0530 Subject: [PATCH 03/15] Align `/complete` and `/submitBulk` form response editing behavior * Updated `/complete` to resolve `FormResponse` using `beneficiaryId` and `formUuid` from the request body, removing the dependency on `responseId` as a query parameter. * Updated `/submitBulk` section editing to match `/complete` behavior by performing in-place `SectionResponse` upserts and per-question delete-and-reinsert operations, instead of deleting and recreating the entire section. --- .../DynamicFormResponseController.java | 3 +-- .../service/DynamicFormResponseService.java | 2 +- .../impl/DynamicFormResponseServiceImpl.java | 23 +++++++++++-------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java index 78a3dd83..3e190816 100644 --- a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java +++ b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java @@ -64,10 +64,9 @@ public ResponseEntity submitForm( @Operation(summary = "Save POST_SUBMIT section answers, status → COMPLETE") @RequestMapping(value = "/complete", method = RequestMethod.POST) public ResponseEntity completeForm( - @RequestParam Long responseId, @Valid @RequestBody FormResponseRequest request, @RequestHeader("JwtToken") String jwtToken) throws IEMRException { - FormResponseDTO dto = responseService.completeForm(responseId, request, jwtToken); + FormResponseDTO dto = responseService.completeForm(request, jwtToken); return ResponseEntity.ok(new ApiResponse(true, "Form completed successfully", dto)); } diff --git a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java index 7a07f23f..6b27ade6 100644 --- a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java +++ b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java @@ -38,7 +38,7 @@ public interface DynamicFormResponseService { FormResponseDTO submitForm(FormResponseRequest request); /** Save POST_SUBMIT section answers and advance status to COMPLETE. */ - FormResponseDTO completeForm(Long responseId, FormResponseRequest request, String jwtToken) throws IEMRException; + FormResponseDTO completeForm(FormResponseRequest request, String jwtToken) throws IEMRException; /** All responses for a beneficiary filtered by form UUID. */ List getResponsesByBeneficiary(Long beneficiaryId, String formUuid); 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 4d1df037..b819afc2 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java @@ -115,23 +115,26 @@ public FormResponseDTO submitForm(FormResponseRequest request) { @Override @Transactional - public FormResponseDTO completeForm(Long responseId, FormResponseRequest request, String jwtToken) throws IEMRException { + public FormResponseDTO completeForm(FormResponseRequest request, String jwtToken) throws IEMRException { String actor = jwtUtil.extractUserId(jwtToken).toString(); - FormResponse formResponse = formResponseRepo.findById(responseId) - .orElseThrow(() -> new NoSuchElementException("FormResponse not found: " + responseId)); - if (!STATUS_SUBMITTED.equals(formResponse.getStatus())) { - throw new IllegalStateException( - "Cannot complete a response in status: " + formResponse.getStatus()); + + FormVersion version = resolveLatestVersion(request.getFormUuid()); + Long formId = version.getDynamicForm().getFormId(); + + List existing = + formResponseRepo.findByBeneficiaryIdAndFormId(request.getBeneficiaryId(), formId); + if (existing.isEmpty()) { + throw new NoSuchElementException( + "FormResponse not found for beneficiaryId=" + request.getBeneficiaryId() + + " formUuid=" + request.getFormUuid()); } + FormResponse formResponse = existing.get(0); + formResponse.setUpdatedBy(actor); formResponse.setStatus(STATUS_COMPLETE); formResponse.setCompletedAt(new Timestamp(System.currentTimeMillis())); formResponse = formResponseRepo.save(formResponse); - FormResponse finalFormResponse = formResponse; - FormVersion version = formVersionRepo.findById(formResponse.getVersionId()) - .orElseThrow(() -> new NoSuchElementException( - "FormVersion not found: " + finalFormResponse.getVersionId())); return processSections(formResponse, request, version, actor); } From 105ede6737c2c560136a42cad6a98a7ea23ecfd4 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Wed, 24 Jun 2026 14:47:52 +0530 Subject: [PATCH 04/15] Add van/sync tracking fields (vanID, parkingPlaceID, vanSerialNo, processed, syncedDate, syncedBy, syncFailureReason) to domain entities for offline mobile data collection support --- .../com/iemr/flw/domain/iemr/DynamicForm.java | 21 +++++++++++++++++ .../iemr/flw/domain/iemr/FormResponse.java | 21 +++++++++++++++++ .../com/iemr/flw/domain/iemr/FormSection.java | 22 ++++++++++++++++++ .../com/iemr/flw/domain/iemr/FormVersion.java | 21 +++++++++++++++++ .../iemr/flw/domain/iemr/OptionCondition.java | 23 +++++++++++++++++++ .../iemr/flw/domain/iemr/QuestionOption.java | 22 ++++++++++++++++++ .../flw/domain/iemr/QuestionResponse.java | 23 +++++++++++++++++++ .../flw/domain/iemr/QuestionValidation.java | 23 +++++++++++++++++++ .../iemr/flw/domain/iemr/SectionQuestion.java | 22 ++++++++++++++++++ .../iemr/flw/domain/iemr/SectionResponse.java | 21 +++++++++++++++++ 10 files changed, 219 insertions(+) diff --git a/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java b/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java index 5ff86faf..9d969b7d 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java @@ -94,6 +94,27 @@ public class DynamicForm { @ToString.Exclude private List versions = new ArrayList<>(); + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; + @PrePersist protected void onCreate() { createdAt = new Timestamp(System.currentTimeMillis()); diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java b/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java index 7c0a09e0..14e0b891 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java @@ -99,6 +99,27 @@ public class FormResponse { @Column(name = "updatedAt", nullable = false) private Timestamp updatedAt; + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; + @PrePersist protected void onCreate() { createdAt = new Timestamp(System.currentTimeMillis()); diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java index 97f02763..d7078c06 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java @@ -37,6 +37,7 @@ import lombok.NoArgsConstructor; import lombok.ToString; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; @@ -90,4 +91,25 @@ public class FormSection { @OneToMany(mappedBy = "formSection", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @ToString.Exclude private List questions = new ArrayList<>(); + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java b/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java index 0e7ec4ae..437a29bc 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java @@ -87,6 +87,27 @@ public class FormVersion { @ToString.Exclude private List sections = new ArrayList<>(); + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; + @PrePersist protected void onCreate() { createdAt = new Timestamp(System.currentTimeMillis()); diff --git a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java index ae54b9ac..281a87d0 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java +++ b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java @@ -35,6 +35,8 @@ import lombok.NoArgsConstructor; import lombok.ToString; +import java.sql.Timestamp; + /** * Conditional action triggered when a specific option is selected. * actionType: SHOW_QUESTION | DISABLE_SECTION_VALIDATION | LOCK_FORM @@ -77,4 +79,25 @@ public class OptionCondition { @Column(name = "updated_by", length = 100) private String updatedBy; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; } 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 f0145523..4d6cbe19 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java @@ -37,6 +37,7 @@ import lombok.NoArgsConstructor; import lombok.ToString; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; @@ -78,4 +79,25 @@ public class QuestionOption { @OneToMany(mappedBy = "questionOption", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @ToString.Exclude private List conditions = new ArrayList<>(); + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java index 23c62ddc..871e31b5 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java @@ -33,6 +33,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.sql.Timestamp; + /** * Stores one answer to a single question within a section response. * MCQ questions produce multiple rows (one per selected option) — no unique constraint on (sectionResponseId, questionId). @@ -76,4 +78,25 @@ public class QuestionResponse { @Column(name = "updated_by", length = 100) private String updatedBy; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java index eb533442..b3253526 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java @@ -38,6 +38,8 @@ import lombok.NoArgsConstructor; import lombok.ToString; +import java.sql.Timestamp; + /** * Server-side validation rule for a question. * validationType: MAX_LENGTH | MIN_DATE | MAX_DATE | REGEX | MANDATORY_IF @@ -75,4 +77,25 @@ public class QuestionValidation { @Column(name = "updated_by", length = 100) private String updatedBy; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java index 1e8581e7..0b571ea2 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java @@ -41,6 +41,7 @@ import lombok.NoArgsConstructor; import lombok.ToString; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; @@ -107,4 +108,25 @@ public class SectionQuestion { @OneToMany(mappedBy = "sectionQuestion", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @ToString.Exclude private List validations = new ArrayList<>(); + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java b/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java index 09fbae82..1fded4c8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java @@ -71,4 +71,25 @@ public class SectionResponse { @Column(name = "updated_by", length = 100) private String updatedBy; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason", length = 255) + private String syncFailureReason; } From 21b71877b48b4aa7870cee265e0c24613471111f Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Thu, 25 Jun 2026 14:56:15 +0530 Subject: [PATCH 05/15] feat(dynamic-form): add Hindi localization fields and completed beneficiaries endpoint - Added `sectionName_hindi`, `questionText_hindi`, and `optionValue_hindi` fields to the FormSection, SectionQuestion, and QuestionOption entities to support Hindi localization. - Added `GET /dynamicForm/response/getCompletedBeneficiaries?formType=` endpoint to return beneficiary IDs with `COMPLETE` status for the specified form type. --- .../DynamicFormResponseController.java | 7 ++ .../com/iemr/flw/domain/iemr/FormSection.java | 3 + .../iemr/flw/domain/iemr/QuestionOption.java | 6 ++ .../iemr/flw/domain/iemr/SectionQuestion.java | 3 + .../com/iemr/flw/dto/iemr/FormSectionDTO.java | 2 + .../iemr/flw/dto/iemr/QuestionOptionDTO.java | 4 + .../iemr/flw/dto/iemr/SectionQuestionDTO.java | 2 + .../iemr/flw/repo/iemr/FormResponseRepo.java | 3 +- .../flw/seeder/TbCounsellingFormSeeder.java | 94 ++++++++++--------- .../service/DynamicFormResponseService.java | 4 + .../impl/DynamicFormResponseServiceImpl.java | 13 +++ 11 files changed, 96 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java index 1261dcf2..65dd7036 100644 --- a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java +++ b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java @@ -23,6 +23,7 @@ import com.iemr.flw.dto.iemr.FormResponseDTO; import com.iemr.flw.dto.iemr.FormResponseRequest; +import com.iemr.flw.masterEnum.FormType; import com.iemr.flw.service.DynamicFormResponseService; import com.iemr.flw.utils.ApiResponse; import com.iemr.flw.utils.exception.IEMRException; @@ -97,4 +98,10 @@ public ResponseEntity getById(@RequestParam Long responseId) { FormResponseDTO dto = responseService.getResponseById(responseId); return ResponseEntity.ok(new ApiResponse(true, "Response fetched successfully", dto)); } + @Operation(summary = "Get beneficiary IDs that have a COMPLETE form response for the given form type") + @RequestMapping(value = "/getCompletedBeneficiaries", method = RequestMethod.GET) + public ResponseEntity getCompletedBeneficiaries(@RequestParam FormType formType) { + List beneficiaryIds = responseService.getCompletedBeneficiaries(formType); + return ResponseEntity.ok(new ApiResponse(true, "Completed beneficiaries fetched successfully", beneficiaryIds)); + } } diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java index d7078c06..8b505ec8 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java @@ -68,6 +68,9 @@ public class FormSection { @Column(name = "sectionName", nullable = false, length = 255) private String sectionName; + @Column(name = "sectionName_hindi", length = 255) + private String sectionNameHindi; + /** PRE_SUBMIT sections are shown before the form's main submit. POST_SUBMIT after. */ @Column(name = "sectionPhase", nullable = false, length = 20) private String sectionPhase; 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 4d6cbe19..192af9ac 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java @@ -64,9 +64,15 @@ public class QuestionOption { @Column(name = "optionLabel", nullable = false, length = 255) private String optionLabel; + @Column(name = "optionLabel_hindi", length = 100) + private String optionLabelHindi; + @Column(name = "optionValue", nullable = false, length = 100) private String optionValue; + @Column(name = "optionValue_hindi", length = 100) + private String optionValueHindi; + @Column(name = "displayOrder", nullable = false) private Integer displayOrder; diff --git a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java index 0b571ea2..5b13d733 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java @@ -73,6 +73,9 @@ public class SectionQuestion { @Column(name = "questionText", nullable = false) private String questionText; + @Column(name = "questionText_hindi", columnDefinition = "TEXT") + private String questionTextHindi; + @Enumerated(EnumType.STRING) @Column(name = "questionType", nullable = false, length = 20) private QuestionType questionType; diff --git a/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java index 4c537106..2db1f8c7 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java @@ -47,6 +47,8 @@ public class FormSectionDTO { @NotBlank(message = "sectionName is required") private String sectionName; + private String sectionNameHindi; + @NotBlank(message = "sectionPhase is required (PRE_SUBMIT or POST_SUBMIT)") private String sectionPhase; 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 bd78c6b4..0328263c 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java @@ -44,9 +44,13 @@ public class QuestionOptionDTO { @NotBlank(message = "optionLabel is required") private String optionLabel; + private String optionLabelHindi; + @NotBlank(message = "optionValue is required") private String optionValue; + private String optionValueHindi; + @NotNull(message = "displayOrder is required") private Integer displayOrder; diff --git a/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java index e19bbeb0..11a81430 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java @@ -49,6 +49,8 @@ public class SectionQuestionDTO { @NotBlank(message = "questionText is required") private String questionText; + private String questionTextHindi; + @NotNull(message = "questionType is required") private QuestionType questionType; 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 830cad08..02077c9f 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java @@ -40,7 +40,8 @@ public interface FormResponseRepo extends JpaRepository { List findByBeneficiaryIdAndFormId(Long beneficiaryId, Long formId); - List findByBeneficiaryId(Long beneficiaryId); + @Query("SELECT r.beneficiaryId FROM FormResponse r WHERE r.formId = :formId AND r.status = :status") + List findBeneficiaryIdsByFormIdAndStatus(@Param("formId") Long formId, @Param("status") String status); @Query("SELECT r.beneficiaryId FROM FormResponse r " + "WHERE r.beneficiaryId IN :benIds " + diff --git a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java index 6c0a248c..edb26b0f 100644 --- a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java +++ b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java @@ -33,6 +33,7 @@ import com.iemr.flw.repo.iemr.DynamicFormRepo; import com.iemr.flw.service.DynamicFormDefinitionService; import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -47,6 +48,7 @@ * @author Piramal Swasthya */ @Component +@RequiredArgsConstructor public class TbCounsellingFormSeeder { private static final Logger log = LoggerFactory.getLogger(TbCounsellingFormSeeder.class); @@ -56,12 +58,6 @@ public class TbCounsellingFormSeeder { private final DynamicFormDefinitionService formService; private final DynamicFormRepo formRepo; - public TbCounsellingFormSeeder(DynamicFormDefinitionService formService, - DynamicFormRepo formRepo) { - this.formService = formService; - this.formRepo = formRepo; - } - @PostConstruct public void seed() { if (formRepo.findByFormUuid(FORM_UUID).isPresent()) { @@ -97,13 +93,13 @@ private DynamicFormDTO buildFormDto() { // ── Section A: Disease Awareness ───────────────────────────────────────────── private FormSectionDTO buildSectionA() { - FormSectionDTO s = section("TB_SEC_A", "Disease Awareness", "PRE_SUBMIT", 1, true, false); + FormSectionDTO s = section("TB_SEC_A", "Disease Awareness", "बीमारी के बारे में जागरूकता", "PRE_SUBMIT", 1, true, false); List qs = new ArrayList<>(); - qs.add(yesNoRadio("TB_A_Q1", "TB disease explained to patient", 1, true)); - qs.add(yesNoRadio("TB_A_Q2", "Transmission route explained", 2, true)); - qs.add(yesNoRadio("TB_A_Q3", "Symptoms explained", 3, true)); - qs.add(yesNoRadio("TB_A_Q4", "Treatment duration explained", 4, true)); - qs.add(textQuestion("TB_A_REMARKS", "Disease awareness notes", 5, false, 500, true)); + qs.add(yesNoRadio("TB_A_Q1", "TB disease explained to patient", "मरीज़ को टीबी बीमारी के बारे में समझाया गया।", 1, true)); + qs.add(yesNoRadio("TB_A_Q2", "Transmission route explained", "ट्रांसमिशन के तरीके के बारे में जानकारी", 2, true)); + qs.add(yesNoRadio("TB_A_Q3", "Symptoms explained", "लक्षणों की जानकारी", 3, true)); + qs.add(yesNoRadio("TB_A_Q4", "Treatment duration explained", "इलाज की अवधि के बारे में जानकारी", 4, true)); + qs.add(textQuestion("TB_A_REMARKS", "Disease awareness notes", "बीमारी के बारे में जानकारी देने वाले नोट्स", 5, false, 500, true)); s.setQuestions(qs); return s; } @@ -111,15 +107,15 @@ private FormSectionDTO buildSectionA() { // ── Section B: Do's and Don'ts ─────────────────────────────────────────────── private FormSectionDTO buildSectionB() { - FormSectionDTO s = section("TB_SEC_B", "Do's and Don'ts", "PRE_SUBMIT", 2, true, false); + FormSectionDTO s = section("TB_SEC_B", "Do's and Don'ts", "करो और ना करो", "PRE_SUBMIT", 2, true, false); List qs = new ArrayList<>(); - qs.add(yesNoRadio("TB_B_Q1", "Cover mouth while coughing — advised", 1, true)); - qs.add(yesNoRadio("TB_B_Q2", "Complete full treatment course — advised", 2, true)); - qs.add(yesNoRadio("TB_B_Q3", "Regular follow-up attendance — advised", 3, true)); - qs.add(yesNoRadio("TB_B_Q4", "Nutritional guidance provided", 4, true)); - qs.add(yesNoRadio("TB_B_Q5", "No smoking / alcohol — advised", 5, true)); - qs.add(yesNoRadio("TB_B_Q6", "Isolation precautions explained", 6, true)); - qs.add(textQuestion("TB_B_REMARKS", "Do's & Don'ts notes", 7, false, 500, true)); + qs.add(yesNoRadio("TB_B_Q1", "Cover mouth while coughing — advised", "खांसते समय मुंह ढकने की सलाह दी जाती है।", 1, true)); + qs.add(yesNoRadio("TB_B_Q2", "Complete full treatment course — advised", "इलाज का पूरा कोर्स पूरा करने की सलाह दी जाती है।", 2, true)); + qs.add(yesNoRadio("TB_B_Q3", "Regular follow-up attendance — advised", "इलाज का पूरा कोर्स पूरा करने की सलाह दी जाती है।", 3, true)); + qs.add(yesNoRadio("TB_B_Q4", "Nutritional guidance provided", "पोषण संबंधी मार्गदर्शन प्रदान किया गया", 4, true)); + qs.add(yesNoRadio("TB_B_Q5", "No smoking / alcohol — advised", "धूम्रपान / शराब न लेने की सलाह दी जाती है।", 5, true)); + qs.add(yesNoRadio("TB_B_Q6", "Isolation precautions explained", "अलगाव सावधानियों के बारे में बताया गया", 6, true)); + qs.add(textQuestion("TB_B_REMARKS", "Do's & Don'ts notes", "क्या करें और क्या न करें - नोट्स", 7, false, 500, true)); s.setQuestions(qs); return s; } @@ -127,11 +123,11 @@ private FormSectionDTO buildSectionB() { // ── Section C: Government Schemes ──────────────────────────────────────────── private FormSectionDTO buildSectionC() { - FormSectionDTO s = section("TB_SEC_C", "Government Schemes", "PRE_SUBMIT", 3, false, false); + FormSectionDTO s = section("TB_SEC_C", "Government Schemes", "सरकारी योजनाएं", "PRE_SUBMIT", 3, false, false); List qs = new ArrayList<>(); - qs.add(yesNoRadio("TB_C_Q1", "Nikshay Poshan Yojana (NPY) eligibility explained", 1, false)); - qs.add(yesNoRadio("TB_C_Q2", "DOTS free treatment explained", 2, false)); - qs.add(textQuestion("TB_C_REMARKS", "Schemes notes", 3, false, 300, true)); + qs.add(yesNoRadio("TB_C_Q1", "Nikshay Poshan Yojana (NPY) eligibility explained", "निक्षय पोषण योजना (एनपीवाई) पात्रता के बारे में बताया गया", 1, false)); + qs.add(yesNoRadio("TB_C_Q2", "DOTS free treatment explained", "DOTS मुफ़्त इलाज के बारे में जानकारी", 2, false)); + qs.add(textQuestion("TB_C_REMARKS", "Schemes notes", "योजनाओं के नोट्स", 3, false, 300, true)); s.setQuestions(qs); return s; } @@ -139,13 +135,13 @@ private FormSectionDTO buildSectionC() { // ── Section D: Treatment Regimen ───────────────────────────────────────────── private FormSectionDTO buildSectionD() { - FormSectionDTO s = section("TB_SEC_D", "Treatment Regimen", "PRE_SUBMIT", 4, true, false); + FormSectionDTO s = section("TB_SEC_D", "Treatment Regimen", "इलाज का तरीका", "PRE_SUBMIT", 4, true, false); List qs = new ArrayList<>(); - qs.add(yesNoRadio("TB_D_Q1", "Regimen explained to patient", 1, true)); - qs.add(yesNoRadio("TB_D_Q2", "Medication names explained", 2, true)); - qs.add(yesNoRadio("TB_D_Q3", "Side effects explained", 3, true)); - qs.add(yesNoRadio("TB_D_Q4", "Importance of adherence explained", 4, true)); - qs.add(textQuestion("TB_D_REMARKS", "Treatment regimen notes", 5, false, 300, true)); + qs.add(yesNoRadio("TB_D_Q1", "Regimen explained to patient", "मरीज़ को इलाज का तरीका समझाया गया।", 1, true)); + qs.add(yesNoRadio("TB_D_Q2", "Medication names explained", "दवाओं के नामों की जानकारी", 2, true)); + qs.add(yesNoRadio("TB_D_Q3", "Side effects explained", "साइड इफ़ेक्ट्स के बारे में जानकारी", 3, true)); + qs.add(yesNoRadio("TB_D_Q4", "Importance of adherence explained", "निर्देशों का पालन करने का महत्व समझाया गया", 4, true)); + qs.add(textQuestion("TB_D_REMARKS", "Treatment regimen notes", "इलाज के तरीके से जुड़े नोट्स", 5, false, 300, true)); s.setQuestions(qs); return s; } @@ -153,20 +149,21 @@ private FormSectionDTO buildSectionD() { // ── Section E: Counselling Completion ──────────────────────────────────────── private FormSectionDTO buildSectionE() { - FormSectionDTO s = section("TB_SEC_E", "Counselling Completion", "PRE_SUBMIT", 5, true, true); + FormSectionDTO s = section("TB_SEC_E", "Counselling Completion", "काउंसलिंग पूरी होना", "PRE_SUBMIT", 5, true, true); List qs = new ArrayList<>(); // Counselling completion status — RADIO: Complete | Refused SectionQuestionDTO statusQ = new SectionQuestionDTO(); statusQ.setQuestionUuid("TB_E_Q1"); statusQ.setQuestionText("Counselling completion status"); + statusQ.setQuestionTextHindi("काउंसलिंग पूरी होने की स्थिति"); statusQ.setQuestionType(QuestionType.RADIO); statusQ.setIsMandatory(true); statusQ.setDisplayOrder(1); statusQ.setVisibleByDefault(true); // "Complete" option — no conditions - QuestionOptionDTO completeOpt = option("Complete", "COMPLETE", 1, List.of()); + QuestionOptionDTO completeOpt = option("Complete", "सम्पूर्ण","COMPLETE", "सम्पूर्ण", 1, List.of()); // "Refused" option — 5 conditions: disable sections A-D + show refusal text box List refusedConditions = new ArrayList<>(); @@ -175,7 +172,7 @@ private FormSectionDTO buildSectionE() { refusedConditions.add(disableSectionValidation("TB_SEC_C")); refusedConditions.add(disableSectionValidation("TB_SEC_D")); refusedConditions.add(showQuestion("TB_E_REFUSAL")); - QuestionOptionDTO refusedOpt = option("Refused", "REFUSED", 2, refusedConditions); + QuestionOptionDTO refusedOpt = option("Refused", "अस्वीकार करना", "REFUSED", "अस्वीकार करना", 2, refusedConditions); List statusOptions = new ArrayList<>(); statusOptions.add(completeOpt); @@ -185,10 +182,10 @@ private FormSectionDTO buildSectionE() { qs.add(statusQ); // Reason for refusal — hidden by default, max 300 chars - qs.add(textQuestion("TB_E_REFUSAL", "Reason for refusal", 2, true, 300, false)); + qs.add(textQuestion("TB_E_REFUSAL", "Reason for refusal", "इनकार का कारण",2, true, 300, false)); // Counsellor remarks — optional, max 500 chars - qs.add(textQuestion("TB_E_REMARKS", "Counsellor remarks", 3, false, 500, true)); + qs.add(textQuestion("TB_E_REMARKS", "Counsellor remarks", "काउंसलर की टिप्पणी", 3, false, 500, true)); s.setQuestions(qs); return s; @@ -197,23 +194,24 @@ private FormSectionDTO buildSectionE() { // ── Section F: Follow Up to TU ─────────────────────────────────────────────── private FormSectionDTO buildSectionF() { - FormSectionDTO s = section("TB_SEC_F", "Follow Up to TU", "POST_SUBMIT", 6, true, true); + FormSectionDTO s = section("TB_SEC_F", "Follow Up to TU", "TU के बाद की कार्रवाई", "POST_SUBMIT", 6, true, true); List qs = new ArrayList<>(); // "Has the patient started TB treatment?" — RADIO: Yes | No SectionQuestionDTO startedQ = new SectionQuestionDTO(); startedQ.setQuestionUuid("TB_F_Q1"); startedQ.setQuestionText("Has the patient started the prescribed TB treatment regimen?"); + startedQ.setQuestionTextHindi("क्या मरीज़ ने टीबी के लिए बताया गया इलाज शुरू कर दिया है?"); startedQ.setQuestionType(QuestionType.RADIO); startedQ.setIsMandatory(true); startedQ.setDisplayOrder(1); startedQ.setVisibleByDefault(true); - QuestionOptionDTO yesOpt = option("Yes", "YES", 1, List.of()); + QuestionOptionDTO yesOpt = option("Yes", "हाँ", "YES", "हाँ", 1, List.of()); List noConditions = new ArrayList<>(); noConditions.add(showQuestion("TB_F_NO_REASON")); - QuestionOptionDTO noOpt = option("No", "NO", 2, noConditions); + QuestionOptionDTO noOpt = option("No", "नहीं", "NO", "नहीं", 2, noConditions); List startedOptions = new ArrayList<>(); startedOptions.add(yesOpt); @@ -225,16 +223,19 @@ private FormSectionDTO buildSectionF() { // Reason for not starting — hidden by default, max 500 chars qs.add(textQuestion("TB_F_NO_REASON", "Reason for not starting the prescribed TB treatment regimen", + "टीबी के लिए तय इलाज का तरीका शुरू न करने का कारण", 2, false, 500, false)); // DOTS centre visit qs.add(yesNoRadio("TB_F_Q2", "Has the patient visited the DOTS centre / referred health facility for treatment collection?", + "क्या मरीज़ इलाज लेने के लिए DOTS सेंटर या रेफर किए गए स्वास्थ्य केंद्र गया है?", 3, true)); // Side effects reported qs.add(yesNoRadio("TB_F_Q3", "Has the patient reported side effects to the treating doctor or DOTS centre?", + "क्या मरीज़ ने इलाज करने वाले डॉक्टर या DOTS सेंटर को साइड इफ़ेक्ट्स के बारे में बताया है?", 4, true)); s.setQuestions(qs); @@ -243,11 +244,12 @@ private FormSectionDTO buildSectionF() { // ── Builder Helpers ─────────────────────────────────────────────────────────── - private FormSectionDTO section(String uuid, String name, String phase, + private FormSectionDTO section(String uuid, String name, String nameHindi, String phase, int order, boolean required, boolean hasSubmitButton) { FormSectionDTO s = new FormSectionDTO(); s.setSectionUuid(uuid); s.setSectionName(name); + s.setSectionNameHindi(nameHindi); s.setSectionPhase(phase); s.setDisplayOrder(order); s.setIsRequired(required); @@ -256,28 +258,30 @@ private FormSectionDTO section(String uuid, String name, String phase, return s; } - private SectionQuestionDTO yesNoRadio(String uuid, String text, int order, boolean mandatory) { + private SectionQuestionDTO yesNoRadio(String uuid, String text, String textHindi, int order, boolean mandatory) { SectionQuestionDTO q = new SectionQuestionDTO(); q.setQuestionUuid(uuid); q.setQuestionText(text); + q.setQuestionTextHindi(textHindi); q.setQuestionType(QuestionType.RADIO); q.setIsMandatory(mandatory); q.setDisplayOrder(order); q.setVisibleByDefault(true); List opts = new ArrayList<>(); - opts.add(option("Yes", "YES", 1, List.of())); - opts.add(option("No", "NO", 2, List.of())); + opts.add(option("Yes", "हाँ","YES","हाँ", 1, List.of())); + opts.add(option("No", "नहीं","NO", "नहीं", 2, List.of())); q.setOptions(opts); q.setValidations(List.of()); return q; } - private SectionQuestionDTO textQuestion(String uuid, String text, int order, + private SectionQuestionDTO textQuestion(String uuid, String text, String textHindi, int order, boolean mandatory, int maxLength, boolean visible) { SectionQuestionDTO q = new SectionQuestionDTO(); q.setQuestionUuid(uuid); q.setQuestionText(text); + q.setQuestionTextHindi(textHindi); q.setQuestionType(QuestionType.TEXT); q.setIsMandatory(mandatory); q.setDisplayOrder(order); @@ -293,11 +297,13 @@ private SectionQuestionDTO textQuestion(String uuid, String text, int order, return q; } - private QuestionOptionDTO option(String label, String value, int order, + private QuestionOptionDTO option(String label, String labelHindi, String value, String valueHindi, int order, List conditions) { QuestionOptionDTO o = new QuestionOptionDTO(); o.setOptionLabel(label); + o.setOptionLabelHindi(labelHindi); o.setOptionValue(value); + o.setOptionValueHindi(valueHindi); o.setDisplayOrder(order); o.setConditions(conditions); return o; diff --git a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java index 6b27ade6..436cae75 100644 --- a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java +++ b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java @@ -23,6 +23,7 @@ import com.iemr.flw.dto.iemr.FormResponseDTO; import com.iemr.flw.dto.iemr.FormResponseRequest; +import com.iemr.flw.masterEnum.FormType; import com.iemr.flw.utils.exception.IEMRException; import java.util.List; @@ -59,4 +60,7 @@ public interface DynamicFormResponseService { * Used by the follow-up notification scheduler. */ List findPendingFollowUps(List formIds, int delayDays); + + /** Returns beneficiary IDs with COMPLETE status for the given form type. */ + List getCompletedBeneficiaries(FormType formType); } 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 a4d13079..8c8cc6ea 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java @@ -34,6 +34,9 @@ import com.iemr.flw.dto.iemr.QuestionResponseDTO; import com.iemr.flw.dto.iemr.SectionAnswerRequest; import com.iemr.flw.dto.iemr.SectionResponseDTO; +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.masterEnum.FormType; +import com.iemr.flw.repo.iemr.DynamicFormRepo; import com.iemr.flw.repo.iemr.FormResponseRepo; import com.iemr.flw.repo.iemr.FormSectionRepo; import com.iemr.flw.repo.iemr.FormVersionRepo; @@ -77,6 +80,7 @@ public class DynamicFormResponseServiceImpl implements DynamicFormResponseServic private static final String STATUS_COMPLETE = "COMPLETE"; private static final String SECTION_STATUS_DONE = "DONE"; + private final DynamicFormRepo dynamicFormRepo; private final FormResponseRepo formResponseRepo; private final SectionResponseRepo sectionResponseRepo; private final QuestionResponseRepo questionResponseRepo; @@ -462,4 +466,13 @@ public List findPendingFollowUps(List formIds, int delayD .map(r -> buildFormResponseDTO(r, List.of())) .collect(Collectors.toList()); } + + @Override + @Transactional(readOnly = true) + public List getCompletedBeneficiaries(FormType formType) { + DynamicForm form = dynamicFormRepo.findByFormTypeAndIsActive(formType, true) + .orElseThrow(() -> new NoSuchElementException( + "No active form found for type: " + formType)); + return formResponseRepo.findBeneficiaryIdsByFormIdAndStatus(form.getFormId(), STATUS_COMPLETE); + } } From fdb1a1f25352b19e05d731cf7d2afd52015b36c6 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Thu, 25 Jun 2026 14:56:15 +0530 Subject: [PATCH 06/15] feat(dynamic-form): add Hindi localization fields and completed beneficiaries endpoint - Added `sectionName_hindi`, `questionText_hindi`, and `optionValue_hindi` fields to the FormSection, SectionQuestion, and QuestionOption entities to support Hindi localization. - Added `GET /dynamicForm/response/getCompletedBeneficiaries?formType=` endpoint to return beneficiary IDs with `COMPLETE` status for the specified form type. --- src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java | 2 +- src/main/java/com/iemr/flw/domain/iemr/FormResponse.java | 2 +- src/main/java/com/iemr/flw/domain/iemr/FormSection.java | 2 +- src/main/java/com/iemr/flw/domain/iemr/FormVersion.java | 2 +- src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java | 2 +- src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java | 2 +- src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java | 2 +- src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java | 2 +- src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java b/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java index 9d969b7d..af183d66 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java @@ -112,7 +112,7 @@ public class DynamicForm { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; @PrePersist diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java b/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java index 14e0b891..7462a561 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java @@ -117,7 +117,7 @@ public class FormResponse { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; @PrePersist diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java index 8b505ec8..b8454716 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java @@ -113,6 +113,6 @@ public class FormSection { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java b/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java index 437a29bc..5902aa21 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java @@ -105,7 +105,7 @@ public class FormVersion { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; @PrePersist 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 192af9ac..2bc02cbd 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java @@ -104,6 +104,6 @@ public class QuestionOption { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java index 871e31b5..c01fc715 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java @@ -97,6 +97,6 @@ public class QuestionResponse { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java index b3253526..b7d41dc1 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java @@ -96,6 +96,6 @@ public class QuestionValidation { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java index 5b13d733..1bd7991b 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java @@ -130,6 +130,6 @@ public class SectionQuestion { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java b/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java index 1fded4c8..36996028 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java @@ -90,6 +90,6 @@ public class SectionResponse { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; } From 5f05f6615d1fbec7046e92395dba6083de61f666 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Fri, 26 Jun 2026 13:20:35 +0530 Subject: [PATCH 07/15] feat(beneficiary): expose GPS coordinates in getBeneficiaryData response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add gpsLatitude, gpsLongitude, digipin, gpsTimestamp, and isGpsUnavailable fields to RMNCHBeneficiaryDetailsRmnch and RMNCHHouseHoldDetails entities, mapping to the columns written by Identity-API's /syncDataToAmrit endpoint. Enable serializeNulls on the Gson builder in BeneficiaryServiceImpl so GPS keys are always present in householdDetails and beneficiaryDetails — null for web-registered records, real values for mobile-registered ones. Co-Authored-By: Claude Sonnet 4.6 --- .../RMNCHBeneficiaryDetailsRmnch.java | 18 +++++++++++++++++ .../identity/RMNCHHouseHoldDetails.java | 8 ++++++++ .../service/impl/BeneficiaryServiceImpl.java | 20 +++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java index e4b634ff..84827388 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java @@ -102,6 +102,24 @@ public class RMNCHBeneficiaryDetailsRmnch { @Column(name = "longitude") private BigDecimal longitude; + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Expose + @Column(name = "digipin") + private String digipin; + + @Expose + @Column(name = "gpsTimestamp") + private Timestamp gpsTimestamp; + + @Expose + @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") + private Boolean isGpsUnavailable = false; + @Expose @Column(name = "menstrualBFDId") private Integer menstrualBFDId; diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java index 3a3ccec8..a0a0adf1 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java @@ -329,4 +329,12 @@ public class RMNCHHouseHoldDetails { @Column(name = "isDeactivate") private Boolean isDeactivate; + @Expose + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Expose + @Column(name = "gpsLongitude") + private Double gpsLongitude; + } diff --git a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java index bbcf59a1..dd1af6f5 100644 --- a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java @@ -1,5 +1,6 @@ package com.iemr.flw.service.impl; +import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Date; import java.text.SimpleDateFormat; @@ -324,6 +325,25 @@ private String getMappingsForAddressIDs(List addressLi if (benAddressOBJ.getPermAddrLine3() != null) benDetailsRMNCH_OBJ.setAddressLine3(benAddressOBJ.getPermAddrLine3()); + // GPS fallback: if not in RMNCH details (syncdatatoamrti not yet called), + // pull from i_beneficiaryaddress (saved during TM-API registration) + if (benDetailsRMNCH_OBJ.getGpsLatitude() == null && benAddressOBJ.getGpsLatitude() != null) + benDetailsRMNCH_OBJ.setGpsLatitude(benAddressOBJ.getGpsLatitude()); + if (benDetailsRMNCH_OBJ.getGpsLongitude() == null && benAddressOBJ.getGpsLongitude() != null) + benDetailsRMNCH_OBJ.setGpsLongitude(benAddressOBJ.getGpsLongitude()); + if (benDetailsRMNCH_OBJ.getDigipin() == null && benAddressOBJ.getDigipin() != null) + benDetailsRMNCH_OBJ.setDigipin(benAddressOBJ.getDigipin()); + if (benDetailsRMNCH_OBJ.getGpsTimestamp() == null && benAddressOBJ.getGpsTimestamp() != null) + benDetailsRMNCH_OBJ.setGpsTimestamp(benAddressOBJ.getGpsTimestamp()); + if (benDetailsRMNCH_OBJ.getIsGpsUnavailable() == null && benAddressOBJ.getIsGpsUnavailable() != null) + benDetailsRMNCH_OBJ.setIsGpsUnavailable(benAddressOBJ.getIsGpsUnavailable()); + + // Map GPS double fields to the exposed latitude/longitude BigDecimal fields for response + if (benDetailsRMNCH_OBJ.getGpsLatitude() != null) + benDetailsRMNCH_OBJ.setLatitude(BigDecimal.valueOf(benDetailsRMNCH_OBJ.getGpsLatitude())); + if (benDetailsRMNCH_OBJ.getGpsLongitude() != null) + benDetailsRMNCH_OBJ.setLongitude(BigDecimal.valueOf(benDetailsRMNCH_OBJ.getGpsLongitude())); + // ----------------------------------------------------------------------------- // related benids From 6ae9ed0d0e9d0771bf3f8be788893fbaa18cfd27 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Fri, 26 Jun 2026 13:21:21 +0530 Subject: [PATCH 08/15] =?UTF-8?q?Committed=2082b00ccf=20with=20only=20the?= =?UTF-8?q?=20three=20files:=20=20=20-=20BeneficiaryServiceImpl.java=20?= =?UTF-8?q?=E2=80=94=20serializeNulls()=20+=20GPS=20fallback=20from=20addr?= =?UTF-8?q?ess=20=20=20-=20RMNCHBeneficiaryDetailsRmnch.java=20=E2=80=94?= =?UTF-8?q?=20gpsLatitude,=20gpsLongitude,=20digipin,=20gpsTimestamp,=20is?= =?UTF-8?q?GpsUnavailable=20fields=20=20=20-=20RMNCHHouseHoldDetails.java?= =?UTF-8?q?=20=E2=80=94=20gpsLatitude,=20gpsLongitude=20fields?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/identity/RMNCHMBeneficiaryaddress.java | 15 +++++++++++++++ .../com/iemr/flw/domain/iemr/OptionCondition.java | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java index c9468688..ea58143d 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java @@ -247,4 +247,19 @@ public class RMNCHMBeneficiaryaddress implements Serializable { @Expose @Column(name = "SyncedDate") private Timestamp SyncedDate; + + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Column(name = "digipin") + private String digipin; + + @Column(name = "gpsTimestamp") + private Timestamp gpsTimestamp; + + @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") + private Boolean isGpsUnavailable = false; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java index 281a87d0..50af2b38 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java +++ b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java @@ -98,6 +98,6 @@ public class OptionCondition { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; } From 0332e9b9641db358a4100552e09002589d925792 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Fri, 26 Jun 2026 13:23:03 +0530 Subject: [PATCH 09/15] Revert "Committed 82b00ccf with only the three files:" This reverts commit 3040a08077d82d27dfd86f29f0fbdd4dc094ec56. --- .../domain/identity/RMNCHMBeneficiaryaddress.java | 15 --------------- .../com/iemr/flw/domain/iemr/OptionCondition.java | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java index ea58143d..c9468688 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java @@ -247,19 +247,4 @@ public class RMNCHMBeneficiaryaddress implements Serializable { @Expose @Column(name = "SyncedDate") private Timestamp SyncedDate; - - @Column(name = "gpsLatitude") - private Double gpsLatitude; - - @Column(name = "gpsLongitude") - private Double gpsLongitude; - - @Column(name = "digipin") - private String digipin; - - @Column(name = "gpsTimestamp") - private Timestamp gpsTimestamp; - - @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") - private Boolean isGpsUnavailable = false; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java index 50af2b38..281a87d0 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java +++ b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java @@ -98,6 +98,6 @@ public class OptionCondition { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason") + @Column(name = "SyncFailureReason", length = 255) private String syncFailureReason; } From 412398551a30e444619521c0ffe82475a25d7844 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Fri, 26 Jun 2026 13:30:30 +0530 Subject: [PATCH 10/15] =?UTF-8?q?Committed=2082b00ccf=20with=20only=20the?= =?UTF-8?q?=20three=20files:=20=20=20-=20BeneficiaryServiceImpl.java=20?= =?UTF-8?q?=E2=80=94=20serializeNulls()=20+=20GPS=20fallback=20from=20addr?= =?UTF-8?q?ess=20=20=20-=20RMNCHBeneficiaryDetailsRmnch.java=20=E2=80=94?= =?UTF-8?q?=20gpsLatitude,=20gpsLongitude,=20digipin,=20gpsTimestamp,=20is?= =?UTF-8?q?GpsUnavailable=20fields=20=20=20-=20RMNCHHouseHoldDetails.java?= =?UTF-8?q?=20=E2=80=94=20gpsLatitude,=20gpsLongitude=20fields?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/identity/RMNCHMBeneficiaryaddress.java | 15 +++++++++++++++ .../com/iemr/flw/domain/iemr/OptionCondition.java | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java index c9468688..ea58143d 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java @@ -247,4 +247,19 @@ public class RMNCHMBeneficiaryaddress implements Serializable { @Expose @Column(name = "SyncedDate") private Timestamp SyncedDate; + + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Column(name = "digipin") + private String digipin; + + @Column(name = "gpsTimestamp") + private Timestamp gpsTimestamp; + + @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") + private Boolean isGpsUnavailable = false; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java index 281a87d0..50af2b38 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java +++ b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java @@ -98,6 +98,6 @@ public class OptionCondition { @Column(name = "Syncedby", length = 50) private String syncedBy; - @Column(name = "SyncFailureReason", length = 255) + @Column(name = "SyncFailureReason") private String syncFailureReason; } From b7488fec8a87216dd9dc7c9ad0b261048a8c0fee Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Fri, 26 Jun 2026 17:01:29 +0530 Subject: [PATCH 11/15] =?UTF-8?q?Committed=2082b00ccf=20with=20only=20the?= =?UTF-8?q?=20three=20files:=20=20=20-=20BeneficiaryServiceImpl.java=20?= =?UTF-8?q?=E2=80=94=20serializeNulls()=20+=20GPS=20fallback=20from=20addr?= =?UTF-8?q?ess=20=20=20-=20RMNCHBeneficiaryDetailsRmnch.java=20=E2=80=94?= =?UTF-8?q?=20gpsLatitude,=20gpsLongitude,=20digipin,=20gpsTimestamp,=20is?= =?UTF-8?q?GpsUnavailable=20fields=20=20=20-=20RMNCHHouseHoldDetails.java?= =?UTF-8?q?=20=E2=80=94=20gpsLatitude,=20gpsLongitude=20fields?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Conflicts: # src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java --- .../flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java | 4 ++++ .../iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java | 3 +++ .../com/iemr/flw/service/impl/BeneficiaryServiceImpl.java | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java index 84827388..dca4f5ee 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java @@ -120,6 +120,10 @@ public class RMNCHBeneficiaryDetailsRmnch { @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") private Boolean isGpsUnavailable = false; + @Expose + @Column(name = "gpsUnavailableReason") + private String gpsUnavailableReason; + @Expose @Column(name = "menstrualBFDId") private Integer menstrualBFDId; diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java index ea58143d..a589ec7a 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java @@ -262,4 +262,7 @@ public class RMNCHMBeneficiaryaddress implements Serializable { @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") private Boolean isGpsUnavailable = false; + + @Column(name = "gpsUnavailableReason") + private String gpsUnavailableReason; } diff --git a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java index dd1af6f5..bc146ca4 100644 --- a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java @@ -337,6 +337,8 @@ private String getMappingsForAddressIDs(List addressLi benDetailsRMNCH_OBJ.setGpsTimestamp(benAddressOBJ.getGpsTimestamp()); if (benDetailsRMNCH_OBJ.getIsGpsUnavailable() == null && benAddressOBJ.getIsGpsUnavailable() != null) benDetailsRMNCH_OBJ.setIsGpsUnavailable(benAddressOBJ.getIsGpsUnavailable()); + if (benDetailsRMNCH_OBJ.getGpsUnavailableReason() == null && benAddressOBJ.getGpsUnavailableReason() != null) + benDetailsRMNCH_OBJ.setGpsUnavailableReason(benAddressOBJ.getGpsUnavailableReason()); // Map GPS double fields to the exposed latitude/longitude BigDecimal fields for response if (benDetailsRMNCH_OBJ.getGpsLatitude() != null) From b92cdeaf45f686e0676de0c5b65cb85fe8b4c9ff Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Tue, 30 Jun 2026 11:02:14 +0530 Subject: [PATCH 12/15] Updated isMandatory field in Section C, so changed in TbCounsellingFormSeeder --- .../java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java index edb26b0f..0e956c9c 100644 --- a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java +++ b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java @@ -125,8 +125,8 @@ private FormSectionDTO buildSectionB() { private FormSectionDTO buildSectionC() { FormSectionDTO s = section("TB_SEC_C", "Government Schemes", "सरकारी योजनाएं", "PRE_SUBMIT", 3, false, false); List qs = new ArrayList<>(); - qs.add(yesNoRadio("TB_C_Q1", "Nikshay Poshan Yojana (NPY) eligibility explained", "निक्षय पोषण योजना (एनपीवाई) पात्रता के बारे में बताया गया", 1, false)); - qs.add(yesNoRadio("TB_C_Q2", "DOTS free treatment explained", "DOTS मुफ़्त इलाज के बारे में जानकारी", 2, false)); + qs.add(yesNoRadio("TB_C_Q1", "Nikshay Poshan Yojana (NPY) eligibility explained", "निक्षय पोषण योजना (एनपीवाई) पात्रता के बारे में बताया गया", 1, true)); + qs.add(yesNoRadio("TB_C_Q2", "DOTS free treatment explained", "DOTS मुफ़्त इलाज के बारे में जानकारी", 2, true)); qs.add(textQuestion("TB_C_REMARKS", "Schemes notes", "योजनाओं के नोट्स", 3, false, 300, true)); s.setQuestions(qs); return s; From 81e29d21b6ed3593c23dc4826a3c23ca8c6dd081 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Thu, 2 Jul 2026 19:16:41 +0530 Subject: [PATCH 13/15] Add optional villageId and providerServiceMapId filters to getCompletedBeneficiaries --- .../flw/controller/DynamicFormResponseController.java | 9 ++++++--- .../java/com/iemr/flw/repo/iemr/FormResponseRepo.java | 9 +++++++++ .../com/iemr/flw/service/DynamicFormResponseService.java | 4 ++-- .../flw/service/impl/DynamicFormResponseServiceImpl.java | 6 ++++-- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java index 65dd7036..49d8e547 100644 --- a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java +++ b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java @@ -98,10 +98,13 @@ public ResponseEntity getById(@RequestParam Long responseId) { FormResponseDTO dto = responseService.getResponseById(responseId); return ResponseEntity.ok(new ApiResponse(true, "Response fetched successfully", dto)); } - @Operation(summary = "Get beneficiary IDs that have a COMPLETE form response for the given form type") + @Operation(summary = "Get beneficiary IDs that have a COMPLETE form response for the given form type, optionally filtered by village and/or provider service map") @RequestMapping(value = "/getCompletedBeneficiaries", method = RequestMethod.GET) - public ResponseEntity getCompletedBeneficiaries(@RequestParam FormType formType) { - List beneficiaryIds = responseService.getCompletedBeneficiaries(formType); + public ResponseEntity getCompletedBeneficiaries( + @RequestParam FormType formType, + @RequestParam(required = false) Integer villageId, + @RequestParam(required = false) Integer providerServiceMapId) { + List beneficiaryIds = responseService.getCompletedBeneficiaries(formType, villageId, providerServiceMapId); return ResponseEntity.ok(new ApiResponse(true, "Completed beneficiaries fetched successfully", beneficiaryIds)); } } 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 02077c9f..66672c16 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java @@ -43,6 +43,15 @@ public interface FormResponseRepo extends JpaRepository { @Query("SELECT r.beneficiaryId FROM FormResponse r WHERE r.formId = :formId AND r.status = :status") List findBeneficiaryIdsByFormIdAndStatus(@Param("formId") Long formId, @Param("status") String status); + @Query("SELECT r.beneficiaryId FROM FormResponse r WHERE r.formId = :formId AND r.status = :status " + + "AND r.beneficiaryId IN (SELECT b.beneficiaryID FROM BenFlowStatus b WHERE b.deleted = false " + + "AND (:villageId IS NULL OR b.villageID = :villageId) " + + "AND (:providerServiceMapId IS NULL OR b.providerServiceMapId = :providerServiceMapId))") + List findBeneficiaryIdsByFormIdAndStatusFiltered(@Param("formId") Long formId, + @Param("status") String status, + @Param("villageId") Integer villageId, + @Param("providerServiceMapId") Integer providerServiceMapId); + @Query("SELECT r.beneficiaryId FROM FormResponse r " + "WHERE r.beneficiaryId IN :benIds " + "AND r.formId = :formId " + diff --git a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java index 436cae75..cca29e2e 100644 --- a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java +++ b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java @@ -61,6 +61,6 @@ public interface DynamicFormResponseService { */ List findPendingFollowUps(List formIds, int delayDays); - /** Returns beneficiary IDs with COMPLETE status for the given form type. */ - List getCompletedBeneficiaries(FormType formType); + /** Returns beneficiary IDs with COMPLETE status for the given form type, optionally filtered by village and/or provider service map. */ + List getCompletedBeneficiaries(FormType formType, Integer villageId, Integer providerServiceMapId); } 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 8c8cc6ea..4553cc06 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java @@ -469,10 +469,12 @@ public List findPendingFollowUps(List formIds, int delayD @Override @Transactional(readOnly = true) - public List getCompletedBeneficiaries(FormType formType) { + public List getCompletedBeneficiaries(FormType formType, Integer villageId, Integer providerServiceMapId) { DynamicForm form = dynamicFormRepo.findByFormTypeAndIsActive(formType, true) .orElseThrow(() -> new NoSuchElementException( "No active form found for type: " + formType)); - return formResponseRepo.findBeneficiaryIdsByFormIdAndStatus(form.getFormId(), STATUS_COMPLETE); + return (villageId != null || providerServiceMapId != null) + ? formResponseRepo.findBeneficiaryIdsByFormIdAndStatusFiltered(form.getFormId(), STATUS_COMPLETE, villageId, providerServiceMapId) + : formResponseRepo.findBeneficiaryIdsByFormIdAndStatus(form.getFormId(), STATUS_COMPLETE); } } From be0d0d69392f3f956b5965ee105c8778a2ea1038 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Thu, 2 Jul 2026 19:36:53 +0530 Subject: [PATCH 14/15] Removing section f from seeder --- src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java index 0e956c9c..4fdd3a2d 100644 --- a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java +++ b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java @@ -85,7 +85,7 @@ private DynamicFormDTO buildFormDto() { sections.add(buildSectionC()); sections.add(buildSectionD()); sections.add(buildSectionE()); - sections.add(buildSectionF()); +// sections.add(buildSectionF()); dto.setSections(sections); return dto; } From f6aca3a8c92d18a7b392c62fd00cb7413b119906 Mon Sep 17 00:00:00 2001 From: Sehjot Singh Pannu Date: Thu, 2 Jul 2026 20:50:21 +0530 Subject: [PATCH 15/15] Removing already existing check in /complete api --- .../service/impl/DynamicFormResponseServiceImpl.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) 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 4553cc06..d1673a0e 100644 --- a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java @@ -124,19 +124,17 @@ public FormResponseDTO completeForm(FormResponseRequest request, String jwtToken FormVersion version = resolveLatestVersion(request.getFormUuid()); Long formId = version.getDynamicForm().getFormId(); + Timestamp now = new Timestamp(System.currentTimeMillis()); List existing = formResponseRepo.findByBeneficiaryIdAndFormId(request.getBeneficiaryId(), formId); - if (existing.isEmpty()) { - throw new NoSuchElementException( - "FormResponse not found for beneficiaryId=" + request.getBeneficiaryId() - + " formUuid=" + request.getFormUuid()); - } - FormResponse formResponse = existing.get(0); + FormResponse formResponse = existing.isEmpty() + ? createFormResponse(request, version, STATUS_SUBMITTED, now) + : existing.get(0); formResponse.setUpdatedBy(actor); formResponse.setStatus(STATUS_COMPLETE); - formResponse.setCompletedAt(new Timestamp(System.currentTimeMillis())); + formResponse.setCompletedAt(now); formResponse = formResponseRepo.save(formResponse); return processSections(formResponse, request, version, actor); }